c#coding guideline その2_20130325

71
Coding Guidelines for C# 3.0, 4.0 and 5.0 のご紹介 2回目 尾崎 義尚 @yoshioms 2013.3.25

Upload: yoshihisa-ozaki

Post on 22-Jun-2015

1.827 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: C#coding guideline その2_20130325

Coding Guidelines for C# 3.0, 4.0 and 5.0 のご紹介 2回目

尾崎 義尚 @yoshioms

2013.3.25

Page 2: C#coding guideline その2_20130325

C# コーディング ガイドライン日本語版

aviva SolutionsのDennis Doomenさんが公開しているコーディングガイドライン

aviva Solutions

オランダにあるコンサルティング会社

ソフトウェア開発のコンサルティングもやってるらしい

http://csharpguidelines.codeplex.com/releases/view/98254

Page 3: C#coding guideline その2_20130325

C# コーディングガイドラインの一例 1/2

もう10年以上前のもので内容が古くなっている

欲しい情報が不足している

不要な情報が含まれている

Page 4: C#coding guideline その2_20130325

C# コーディングガイドラインの一例 2/2

そもそも情報が少なすぎる

4ページしかない

っていうか、命名規約しかない。

https://docs.google.com/presentation/d/1ajbucKh09cSD_N3m5iUV9jBi7Ji34QczxD6xnjwfcIo/edit

Page 5: C#coding guideline その2_20130325

時代に合わせた

コーディング標準が

必要!

Page 6: C#coding guideline その2_20130325

さまざまな反響

Kokudoriさんの読評がすごい!

http://d.hatena.ne.jp/Kokudori/20130214/1360868503

Page 7: C#coding guideline その2_20130325

文書の基本構造

重要度に応じて必要な規約を選択する

❶ 絶対に守るべきガイドライン

❷ 強くお薦めするガイドライン

❸ 状況に応じては推奨するガイドライン

Page 8: C#coding guideline その2_20130325

全部を採用する必要はありません。

プロジェクトにあった選択を。

Page 9: C#coding guideline その2_20130325

インターフェイスは小さく、集中的であるべきである

目的と役割を明確に説明できる名前を持つべきである

関連性の薄いメンバーを組み合わせてはならない

メンバーの責務を元にメンバーを分離して、呼び出し元は特定のタスクに関連するインターフェイスを呼び出すか実装する

インターフェイス分離原則として一般的に知られている

AV1003

Page 10: C#coding guideline その2_20130325

クラスを分離するためにインターフェイスを使用する

インターフェイスはクラスを切り離すために非常に効果的なメカニズムである。

双方向の関係性を防ぐことができる

別の実装に置き換えることが容易である

本番環境以外で高価な外部サービスやリソースを一時的にスタブに置き換えることができる

ユニットテストでダミー実装やフェイクオブジェクトに置き換えることができる

特定のインターフェイスが要求されても、依存性注入フレームワークを使って、どのクラスを選択するかを集中管理できる

AV1005

Page 11: C#coding guideline その2_20130325

派生クラスは、ベースクラスであるかのように処理を実行できなくてはならない

派生クラスを参照された場合でも、ベースクラスの参照と同じように使用できるようにするべきである

Note このルールは、S.O.L.I.D. 原則のひとつであるリスコフの置換原則としても知られている

AV1011

Page 12: C#coding guideline その2_20130325

オブジェクトが依存するほかのオブジェクトを公開するのを避ける

デメテルの法則に違反している可能性がある。

オブジェクトは依存するほかのクラスを公開するべきではない。

将来それを置き換える機会を制限してしまう。

Note 流れるようなインターフェイスパターンはこのルールに違反しているように見えるが、メソッドチェーンを可能にするために自分自身を返しているだけである。

例外制御の反転や依存性注入のためだけにプロパティを公開するのはOK

AV1014

Page 13: C#coding guideline その2_20130325

ステートフルなオブジェクトを静的メンバーとして公開してはいけない

ステートフルなオブジェクトとは、多くのプロパティ多くの振る舞いが含まれているオブジェクト

静的プロパティや静的メソッドを通じて、オブジェクトを他のオブジェクトに公開した場合、リファクタリングやユニットテストが難しく、ステートフルオブジェクトに依存したクラスになってしまう。

HttpContext.Currentプロパティはこの例のひとつ

ひどいコードとしてHttpContextのソースコードを参照して欲しい

AV1125

Page 14: C#coding guideline その2_20130325

コレクションクラスの代わりにIEnumerable<T>やICollection<T>を返す

呼び出し元で内部コレクションを変更できないようにしたいので、配列、リストなどのコレクションクラスを直接返してはいけない。代わりにIEnumerable<T>や、呼び出し元でカウントが必要ならICollection<T>を返す。

Note .NET 4.5を使っているのであれば、 IReadOnlyCollection<T>、IReadOnlyList<T>、IReadOnlyDictionary<TKey, TValue>も使用することができる。

AV1130

Page 15: C#coding guideline その2_20130325

いくつかの種類のステータスで返すよりも例外をスローする

成功か失敗かを報告する値を返すコードベースでは、ネストされたifステートメントですべてのコードで振り分けする傾向にある。呼び出し元はよく戻り値のチェックを忘れる。

構造化例外ハンドリングは、例外のスロー、高いレイヤでのキャッチや例外の置き換えを許可している。ほとんどのシステムで、予期しない状況での例外のスローはとても一般的である。

AV1200

例外はコストが高いのでステータスを返したい。予期しない状況であれば、例外を返してもよい。

Page 16: C#coding guideline その2_20130325

リッチで意味のある例外メッセージテキストを提供する

メッセージは、例外が発生した理由を説明して、例外を避けるためにはどうする必要があるかを明確に説明する必要がある。

AV1202

開発者向けという意味なら問題ない。ユーザー向けというのであれば、リリースまでに修正するべきである。

Page 17: C#coding guideline その2_20130325

非同期コード内の例外をきちんと処理する

async/awaitやTaskのコードで例外をスローまたは処理するときは、以下の2つのルールを忘れてはいけない。

async/await ブロックとTaskのアクション で例外が発生したときは、awaitしているものに伝搬される

非同期ブロックの前のコードで発生した例外は、呼び出し元に伝搬される

AV1215

Page 18: C#coding guideline その2_20130325

各イベントを発生させるためにprotected virtualメソッドを使用する

rotectedメソッドをオーバーライドすることで、派生クラスからベースクラスのイベントを処理することができる。

protected virtualメソッドの名前は、イベントと同じ名前にOnをつけた名前にするべきである。

たとえば、TimeChangedというイベントのprotected virtualメソッドはOnTimeChangedという名前にする。

Note protected virtualメソッドをオーバーライドした派生クラスは、ベースクラスの実装を呼び出す必要はない。ベースクラスは、実装が呼び出されなかったとしても正しく動作できなくてはならない。

AV1225

長いけど要は、OnXXXでイベント処理できるように作れってことね。

Page 19: C#coding guideline その2_20130325

該当する場合は、ジェネリック制約を使用する

ジェネリック型かメソッドのobject型からキャストする代わりにwhere制約やas演算子をジェネリックパラメータの正確な特性を指定するために使用する。例えば:

AV1240

class SomeClass{}

// Don'tclass MyClass<T>{

void SomeMethod(T t){

object temp = t;SomeClass obj = (SomeClass) temp;

}}

// Doclass MyClass<T> where T : SomeClass{

void SomeMethod(T t){

SomeClass obj = t;}

}

要はwhereを使えってことね。

Page 20: C#coding guideline その2_20130325

二重否定の条件を避ける

customer.HasNoOrdersのようなプロパティは間違っていないが、以下のように否定条件で使用するのは避ける :

bool hasOrders = !customer.HasNoOrders;

二重否定は単純な表現よりも理解が難しく、人々は二重否定を簡単に読むことができない。

AV1502

二重否定だけじゃなくて、HasNo~というプロパティ名はどうだろう?! がNotというのは視認性が低い。(言語レベルの問題)

Page 21: C#coding guideline その2_20130325

変数の宣言と初期化は可能な限り遅らせる

CとVisual Basicのようにすべての変数をブロックの最初に宣言するスタイルは避け、各変数が必要になった時点で定義して初期化する。

AV1521

C(99)やVBでも最初に宣言しなくても大丈夫になってるよ。

Page 22: C#coding guideline その2_20130325

ステートメントをわけるよりもオブジェクトやコレクションの初期化子を使用する

以下のようにする代わりにAV1523

var startInfo = new ProcessStartInfo(“myapp.exe”);

startInfo.StandardOutput = Console.Output;

startInfo.UseShellExecute = true;

オブジェクト初期化子を使用する。var startInfo = new ProcessStartInfo(“myapp.exe”)

{

StandardOutput = Console.Output,

UseShellExecute = true

};

同様に、以下の代わりに

var countries = new List<string> { “Netherlands”, “United States” };

var countries = new List<string>();

countries.Add(“Netherlands”);

countries.Add(“United States”);

コレクションやディクショナリ初期化子を使用する。

Immutableにするためにコンストラクタで渡すことも多い

Page 23: C#coding guideline その2_20130325

ループ変数をforやforeachループの中で変更しない

ループ変数を一か所だけでなく、ループ処理の中で変更すると通常は混乱をきたすことになる。このルールはforeachループにも適用されるが、通常は列挙子がコレクションの変更を検出する。

AV1530

for (int index = 0; index < 10; ++index)

{

if (some condition)

{index = 11; // 誤り! 代わりに‘break’ か‘continue’を使用する

}

}

3つずつ進めるために内部でインクリメントすることがある+3するよりもインクリメントのほうがクロック数を節約できる

Page 24: C#coding guideline その2_20130325

ループのネストを避ける

ネストされたループを持つメソッドは単一のループのものより理解しづらい。実際のところ、ネストされたループを持つほとんどのケースは、データを結合するためにfrom キーワードを2回以上使用してLINQクエリに置き換えることで大幅にシンプルにできる。

AV1532

fromというよりもjoin

Page 25: C#coding guideline その2_20130325

if、else、while、for、foreach、case などのキーワードの後に常にブロックを追加する

これはフォーム内のステートメントの混乱も防ぐこともできる:AV1535

if (b1) if (b2) Foo(); else Bar(); // どちらの ‘if’ が ‘else’に進むのか

// 正しくは:

if (b1)

{

if (b2)

{

Foo();

}

else

{

Bar();

}

}

上のコードには悪意がある。面倒なので書かないことも多い。(書かないことがある人が多かった)

Page 26: C#coding guideline その2_20130325

すべてのif-else-ifステートメントはelseで終わる

例えば、AV1537

void Foo(string answer)

{

if (answer == "no")

{

Console.WriteLine("You answered with No");

}

else if (answer == "yes")

{

Console.WriteLine("You answered with Yes");

}

else

{// ここに到達したときになにが起こるのか 無視 そうじゃない場合は、

// throw an InvalidOperationException.

}

}

カバレッジを下げてしまうのでちょっと。。。

Page 27: C#coding guideline その2_20130325

複数のreturn ステートメントを控える

ひとつの入り口、ひとつの出口は可読性の高いフロー制御を維持する原則である。ただし、メソッドが非常に小さく、ガイドラインAV1500に準拠している場合、複数のreturnステートメントは、何カ所かで更新されるbooleanフラグを管理するよりも可読性を向上させる。

AV1540

コードが長いときには途中でreturnしてもよいのでは?無駄にひとつのメソッドにとどまる必要はない。

Page 28: C#coding guideline その2_20130325

単純な(条件付きの)割り当ての代わりにif-else ステートメントを使用しない

直接の意図を表現する。例えば、以下よりも AV1545

bool pos;

if (val > 0)

{

pos = true;

}

else

{

pos = false;

}

bool pos = (val > 0); // 初期化

以下のように書く。

return someString ?? “Unavailable”;

または、以下の代わりに

以下のように書く

string result;

if (someString != null)

{

result = someString;

}

else

{

result = “Unavailable”;

}

return result;

Page 29: C#coding guideline その2_20130325

他のオーバーロードからもっともパラメータの多いメソッドを呼び出す

このガイドラインは、オプショナル引数を持つオーバーロードにのみ適用される。例えばAV1551

public class MyString

{

private string someText;

public MyString(string text)

{

this.someText = text;

}

public int IndexOf(string phrase)

{

return IndexOf(phrase, 0, someText.Length);

}

public int IndexOf(string phrase, int startIndex)

{

return IndexOf(phrase, startIndex, someText.Length - startIndex );

}

public virtual int IndexOf(string phrase, int startIndex, int count)

{

return someText.IndexOf(phrase, startIndex, count);

}

}

MyStringクラスはIndexOf の3つのオーバーロードを提供するが、そのうち2つはもっともパラメータの多いものを呼び出す。同じルールがクラスのコンストラクターに適用される; もっとも完全なオーバーロードを実装して、他のオーバーロードからthis()初期化子を使って呼び出す。また、同じ名前のパラメータは同じすべてのオーバーロードで同じ位置に現れるようにするべきである。

重要 派生クラスでこれらのメソッドのオーバーロードを可能にしたい場合、もっとも完全なオーバーロードをprotected virtualにして、すべてのオーバーロードから呼ばれるようにする。

Page 30: C#coding guideline その2_20130325

bool フラグを受け取るメソッドを避ける

以下のようなシグニチャのメソッドについて考えてみよう:AV1564

public Customer CreateCustomer(bool platinumLevel) {}

Customer customer = CreateCustomer(true);

フラグを受け取るメソッドは2つ以上のことをやっていることが多く、2つ以上のメソッドにリファクタリングする必要がある。代替のソリューションとしてはフラグを列挙に置き換えることである。

一見するとこのシグニチャは問題ないように見えるが、このメソッドを呼び出すと、完全に目的を見失うことになる:

Page 31: C#coding guideline その2_20130325

略称を使用しない

例えば、OnBtnClickではなくOnButtonClickを使用する。一文字の変数名を避け、iやqではなく、indexやqueryを使用する。

例外あなたの領域(ドメイン)で広く受け入れられて、よく知られている略称。例えば、UserInterfaceではなくUIなど。

AV1706

Page 32: C#coding guideline その2_20130325

メンバー、パラメータ、変数には、型ではなく意味に応じた名前をつける

機能名を使用する。例えば、GetIntではなくGetLengthを使用する。

名前にEnum、Class 、Struct のような用語を使用しない。

コレクション型の識別子には、複数形の名前をつける。

AV1707

Page 33: C#coding guideline その2_20130325

型名には、名詞、名詞句、形容詞句を使用する

悪い例としてSearchExamination(検査するため検索ページ)、Common (名詞で終わらない、目的を説明していない) 、SiteSecurity (名前は技術的にはOKだが、目的についてなにも説明していない)があげられる。よい例としては、BusinessBinder、SmartTextBox、EditableSingleCustomerがある。

クラスにUtilityやHelperなどの用語は使用しない。このようなクラスは通常、静的クラスであり、オブジェクト指向の原則(AV1008も参照)を考慮していない。

AV1708

Page 34: C#coding guideline その2_20130325

ジェネリック型パラメータには説明的な名前を使用する

常にパラメータ名のプレフィックスにTを使用する

一文字の名前が完全にそれを説明しない限り常に説明的な名前を使用し、長い名前に価値がない場合は、ひともじTを型パラメータとして使用する。

型パラメータの名前には、設定された制約を示す名前を検討する。例えば、ISessionの制約があるパラメータはTSessionと呼ばれる。

AV1709

Page 35: C#coding guideline その2_20130325

プロパティ名を適切につける

プロパティ名には、名詞、名詞句、ときどき形容詞句を使用する

Booleanプロパティには肯定的なフレーズを使用する。例えばCantSeekではなくCanSeek

Booeanプロパティには、Is、 Has、 Can、 Allows、Supportsなどのプレフィックスを検討する

型と同じ名前のプロパティを検討する。列挙型に強い型付けされているプロパティは、列挙型と同じ名前を使用することができる。例えば、CacheLevelという名前の列挙型がある場合、その中のひとつの値を返すプロパティ名もCacheLevelにすることができる

AV1715

Cantは、英語の言語的な問題。Tの発音は微妙

Page 36: C#coding guideline その2_20130325

動詞と目的語をペアにしたメソッド名を使用する

ShowDialogのように動詞-目的語をペアにしたメソッド名を使用する。よい名前は、メンバーを「どうする(What)」かのヒントを与えるべきであり、可能であれば、「なぜ(Why)」も含める。また、メソッド名にはAndを含めてはいけない。これは、メソッドがひとつ以上のことをしていることを暗示しており、AV1115で説明されている単一責任の原則に違反している。

AV1720

Andはだめだけど、Orはいいの?String.IsNullOrEmpty()

Page 37: C#coding guideline その2_20130325

イベント名には、動詞か動詞句を使用する

イベント名には、動詞か動詞句を使用する。例えば: Click、Deleted、 Closing、 Minimizing、Arriving。例えば、Searchイベントは以下のように宣言される:

public event EventHandler<SearchArgs> Search;

AV1735

意外とing→edという順番を知らない人もいる。英語は不規則変化するのがちょっと

Page 38: C#coding guideline その2_20130325

非同期メソッドの接尾辞にはTaskAsyncまたはAsyncを使用する

一般的な規約では、TaskやTask<TResult>を返すメソッドは、接尾辞にAsyncを使用するが、そのようなメソッドがすでに存在している場合、代わりにTaskAsync を使用する。

AV1755

Page 39: C#coding guideline その2_20130325

匿名メソッドではなくラムダ式を使用する

ラムダ式は、匿名メソッドよりもはるかにエレガントである。なので、以下の代わりに

AV2221

Customer c = Array.Find(customers, delegate(Customer c)

{

return c.Name == “Tom”;

});

ラムダ式を使用する。

Customer c = Array.Find(customers, c => c.Name == “Tom”);

また、以下の方がさらによい。

var customer = customers.Where(c => c.Name == “Tom”);

delegateは負の遺産

Page 40: C#coding guideline その2_20130325

すべてのpublic、protected、internalタイプとメンバーにドキュメントを記述する

どこかであなたのクラスが使われたときにVisual Studioでドキュメントがポップアップされるようにドキュメントを記述する。あなたのクラスを正しくドキュメント化することによって、ツールはクラスのドキュメントを生成することができる。

AV2305

コメントをローカライズできないのが問題国際化対応できるようにして欲しい

Page 41: C#coding guideline その2_20130325

他の開発者を念頭に置いてXMLドキュメントを記述する

他の開発者を念頭に置いて、型のドキュメントを記述する。

彼または彼女がソースコードにアクセスできないことを想定して、その型の機能を最大限に活用できる方法を説明するようにする。

AV2306

多言語対応が難しい。ローカライズできるようにして欲しい。

Page 42: C#coding guideline その2_20130325

インラインコメントを避ける

コメントを使ってコードのブロックを説明する必要性を感じた場合、明確な名前を持つブロックに置き換えることを検討する。

AV2310

日本人がソースコードを文章として読めるかどうか。

Page 43: C#coding guideline その2_20130325

使えるオブジェクトを返すコンストラクターだけを作成する

オブジェクトが使用可能になるまでに追加でプロパティに値をセットする必要がないように設計する。

ただし、コンストラクターに3つより多いパラメータが必要 (AV1561

に違反している) な場合、そのクラスは責務を持ちすぎている(AV1000に違反) 可能性がある。

AV1001

Page 44: C#coding guideline その2_20130325

複数の実装をサポートするためにベースクラスではなくインターフェイスを使用する

クラスに拡張ポイントを公開したい場合、ベースクラスではなくインターフェイスを公開した方がよい

拡張ポイントのユーザーが望まない動作をするベースクラスの実装を強要したくないはず

ただし、開始点としてデフォルト実装(abstract)を提供することで便利になるかもしれない

AV1004

Page 45: C#coding guideline その2_20130325

静的クラスを避ける

拡張メソッドコンテナをのぞいて静的なクラスは粗悪な設計のコードに繋がることが多い。

またすごいハックツールを使いたい場合を除いて、テストの分離が難しくなる。

Note 静的クラスがどうしても必要な場合、Staticとしてマークしてコンパイラがインスタンスメンバーとクラスをインスタンス化することを防ぐようにする。これで明示的なprivateコンストラクターを作成する必要がなくなる。

AV1008

Page 46: C#coding guideline その2_20130325

プロパティの代わりにメソッドを使用する

フィールドの値をセットするよりも負荷が大きいもの

Object.ToString メソッドのように変換を意味するもの

引数が同じでも、呼び出されるたびに異なる結果を返す場合。例えば、NewGuidメソッドは、呼び出されるたびに違う値を返すもの

直接関係ないプロパティの内部状態によって異なる(コマンドとクエリ分離に違反)など、操作の副作用が発生するもの

例外内部キャッシュへの投入や遅延読み込みはよい例である。

AV1105

プロパティとメソッドの使い分け基準

Page 47: C#coding guideline その2_20130325

プリミティブよりもドメイン固有の値型を検討する

string, int, decimalなどを使うのではなく、ISBN番号、Eメールアドレスや金額などドメイン固有の型など、データとそれに適用されるバリデーションルールの両方をラップした専用の値オブジェクトの作成を検討する。

これを行うことにより、同じビジネスルールが複数存在することがなくなり、保守性とバグの防止の両方が改善される。

AV1140

わかるけど面倒なことも多い。簡単にできる言語もある。

Page 48: C#coding guideline その2_20130325

もっとも適した例外をスローする

例えば、メソッドが引数にnullを受け取った場合、基本型のArgumentExceptionではなく、ArgumentNullExceptionをスローするべきである。

AV1205

Page 49: C#coding guideline その2_20130325

プロパティ変更イベントの提供を検討する

プロパティが変更された時に発生するイベントの提供を検討する。PropertyChangedという名前のイベントを付けるべきで、Propertyはこのイベントに関連づけられたプロパティの名前に置き換えられるべきである。

Note クラスが、対応するイベントが必要な多くのプロパティを持っている場合、INotifyPropertyChangedインターフェイスの実装を検討する。これはプレゼンテーションモデルとModel-View-ViewModelパターンでよく使用されている。

AV1230

Page 50: C#coding guideline その2_20130325

アセンブリ名にはそれに含まれる名前空間を使用する

すべてのDLLは<Company>.<Component>.dll のパターンで、<Company>は、企業名で、<Component>はひとつ以上のドットで区切られた節を含んでいる名前を使用するべきである。例えば、

AvivaSolutions.Web.Controls.dll.

例として、アセンブリで公開しているAvivaSolutions.Web.Binding名前空間の下のグループを検討してみよう。ガイドラインによるとアセンブリは次のように呼ばれるべきである。

AvivaSolutions.Web.Binding.dll.

例外無関係な複数の名前空間からクラスを集めてひとつのアセンブリに結合する場合、アセンブリの最後にCoreをつけることを検討する。ただし、名前空間にはつけない。例えば、

AvivaSolutions.Consulting.Core.dll.

AV1505

Page 51: C#coding guideline その2_20130325

ソースファイル名にはそれに含まれる型を使用する

ファイルの名前にはPascal Caseを使用して、アンダースコアを使用しない。

AV1506

Page 52: C#coding guideline その2_20130325

ソースコードファイルに含めるのはひとつの型に制限する

例外ネストされた型は明らかに同じファイルの一部である必要がある。

AV1507

Page 53: C#coding guideline その2_20130325

ソースファイル名には、partialタイプの論理機能をつける

Partialタイプを使用して、ファイルごとに一部を割り当てている場合、それぞれのファイル名は論理パートの後にパートが果たしていることをつける。例えば、

// In MyClass.cs

public partial class MyClass

{...}

// In MyClass.Designer.cs

public partial class MyClass

{...}

AV1508

Page 54: C#coding guideline その2_20130325

完全な型名の代わりにusing ディレクティブを使用する

名前の衝突を防ぐために完全な名前を制限する。例えば、以下のように使用しない。

var list = new System.Collections.Generic.List<string>();

代わりに以下のようにする。

using System.Collections.Generic;

var list = new List<string>();

名前の衝突を防ぐ必要がある場合、usingディレクティブを使って別名を割り当てる:

using Label = System.Web.UI.WebControls.Label;

上記3つの例では、期待している型が明確である。より詳細な varによるメリット・デメリットは、Eric Lippert氏の型推論を使うかどうかを参照して欲しい。

AV1510

まじで?あんまりみたことがない。

Page 55: C#coding guideline その2_20130325

パラメータを一時変数として使用しない

一時的な状態を保持する便利な変数としてパラメータを使用してはならない。一時的な変数と型が同じであったとしても、一時変数としての目的を反映していない。

AV1568

使っちゃうこともある。きちんとした変数がついていれば使われないかも

Page 56: C#coding guideline その2_20130325

変数、パラメータ、型メンバーに数字を含めない

ほとんどのケースで明確に意図を示さない名前をつけているのは怠けているだけである。

AV1704

COMを否定したいんだよね?

Page 57: C#coding guideline その2_20130325

メンバー名は、関連する.NET Frameworkクラスのメンバーと同様にする

.NET開発者はすでにフレームワークユーザーのパターンになれているため、同じパターンのものはあなたのクラスの助けになる

例えば、コレクションのように振る舞うクラスを定義した場合、AddItem、Delete、NumberOfItemsではなく、Add、Remove 、Countのようなメンバーを提供する。

AV1711

ドメインの言葉があれば、それを使った方がいいかも。DeleteとRemoveは混乱しているかも。

Page 58: C#coding guideline その2_20130325

名前空間名には、名前、レイヤ、動詞、機能を使用する

例えば、以下の名前空間はこのガイドラインのよい例である。

AvivaSolutions.Commerce.Web

NHibernate.Extensibility

Microsoft.ServiceModel.WebApi

Microsoft.VisualStudio.Debugging

FluentAssertion.Primitives

CaliburnMicro.Extensions

Note 名前空間には型の名前を含めてはいけないが、複数形の名詞、例えば Collectionsは通常OKである。

AV1725

Page 59: C#coding guideline その2_20130325

事前イベントと事後イベントには、-ing と -ed を使用する

例えば、ウィンドウが閉じる前に発生するcloseイベントはClosing

ウィンドウが閉じた後で発生するイベントはClosed

事前、または事後イベントを示すためにBeforeやAfterプレフィックスやサフィックスを使用してはいけない。

DeletingとDeletedイベントをBeginDeleteとEndDeleteとしてイベントを定義するのは避ける。

Deleting: オブジェクトが削除される前に発生する

Delete:オブジェクトがイベントハンドラで削除される必要がある時に発生する

Deleted: オブジェクトがすでに削除されたときに発生する

AV1737

Page 60: C#coding guideline その2_20130325

イベントハンドラのプレフィックスとしてOnを使用する

イベントを処理するメソッドにはOnをプレフィックスにするとよい。例えば、Closingイベントを処理するメソッド名はOnClosingにする。

AV1738

Page 61: C#coding guideline その2_20130325

重要でないラムダパラメータにはアンダースコアを使用する

例えば、イベントをサブスクライブするのにラムダステートメントを使用する場合、イベントの実際のパラメータは重要でないことをより明確にするため、以下の規則を使用する。

button.Click += (_, __) => HandleClick();

AV1739

Page 62: C#coding guideline その2_20130325

クラス内の拡張メソッドのグループは、Extensionsサフィックスを使用する

拡張メソッドの名前が、他のメンバーや拡張メソッドと競合する場合、クラス名にプレフィックスを付ける必要がある。Extensionsサフィックスを持つクラスは可読性を向上させる。

AV1745

Page 63: C#coding guideline その2_20130325

IEnumerable<T>が空かどうかを確認するためにAny()の使用を検討する

メソッドや他のメンバーがCountプロパティを公開しないIEnumerable<T>や他のコレクションクラスを返す場合、コレクションにアイテムが含まれているかどうかを判定するためにCount()ではなくAny()拡張メソッドを使用する。

Count()を使用する場合、コレクション全体を反復する重大なインパクト(それが実際に永続ストアへのIQueryable<T>など)を与えるリスクがある。

Note IEnumerable<T>を返す場合、AV1130 で説明されているようにオーナーが外部からの編集を防ぎ、.NET 4.5以上で開発している場合は、新しい読み取り専用クラスを検討する。

AV1800

Page 64: C#coding guideline その2_20130325

ローカライズされたリソースを参照するプロパティ、変数、フィールドに適切な名前をつける

このトピックのガイドラインは、エラーメッセージやメニューテキストのようにローカライズされたリソースに適用される。

リソースキーにPascal caseを使用する

短い識別子よりも説明的なものを提供する。可能であれば簡潔にするが、読みやすさを重視する。

リソースの名前には、英数字のみを使用する。

AV2205

Page 65: C#coding guideline その2_20130325

デプロイメントで変更される文字列をハードコードしない

例えば、接続文字列やサーバーアドレスなど。

ConfigurationManagerクラスのConnectionStringsプロパティやVisual

Studioによって生成されたSettingsクラスなどのResourcesを使用する。

実際の値は、app.configやweb.config(と間違えなくカスタム構成ストア)で維持する。

AV2207

Page 66: C#coding guideline その2_20130325

AssemblyInfo.csファイルの属性を正しく埋める

会社名、説明、著作権、バージョンなどの属性が埋められていることを確認する。すべてのアセンブリで、バージョンなどのフィールドに同じ値がきちんと埋められていることを確認するひとつの方法は、AssemblyInfo.csの対応する属性をソリューション内のプロジェクトで共有されるSolutionInfo.csに移動することである。

AV2215

そうだよねー。でも面倒

Page 67: C#coding guideline その2_20130325

シンプルな表現へのLINQ(クエリ式)は避ける

以下の記述よりも

var query = from item in items where item.Length > 0;

System.Linq名前空間の拡張メソッドを使用する。

var query = items.Where(i => i.Length > 0);

LINQクエリは可読性のために複数行で書くべきなので、2番目の例の方がもう少し可読性が高い。

AV2220

クエリ式自体それほど使っていない。拡張メソッドがほとんど。

Page 68: C#coding guideline その2_20130325

MSDNスタイルのドキュメントを記述する

開発者がドキュメントをより簡単に見つけられるように以下のMSDN

オンラインヘルプのスタイルと単語を選択する。

Tip GhostDocは、ショートカットキーを使用してコードをドキュメント化する起点を生成することができる。

AV2307

Page 69: C#coding guideline その2_20130325

後で作業を追跡できるようにするためにコメントを使用しない

TODOなどのコメントを使って、コードのブロックややるべき作業を記述することは、やるべき作業を追跡する合理的な方法に見えるかもしれない。

しかし実際には、誰もそのようなコメントを探すことはない。残作業を追跡するためにTeam Foundation Serverなどの作業アイテムトラッキングシステムを使用する。

AV2318

VSでもTODOリストが出てくる。

Page 70: C#coding guideline その2_20130325

企業ごとの名前空間の並び順とグループ

AV2402

そうなんだ?コーディングガイドラインと一緒に公開されているReSharperルールセットを入れると自動的にやってく

れる。

// Microsoft 名前空間を最初にする

using System;

using System.Collections;

using System.XML;

// その後、他の名前空間をアルファベット順に

using AvivaSolutions.Business;

using AvivaSolutions.Standard;

using Telerik.WebControls;

using Telerik.Ajax;

Page 71: C#coding guideline その2_20130325

全部を採用する必要はありません。

プロジェクトにあった選択を。