C# のコーディング規則 (C# プログラミング ガイド)
C# 言語仕様では、コーディング規約は定義されていません。 ただし、このトピックのガイドラインは、サンプルおよびドキュメントを開発するためにマイクロソフトによって使用されます。
コーディング規約には、次の目的があります。
コードの見た目が統一されるため、コードを読むときに、レイアウトではなく内容に重点を置くことができます。
これにより、経験に基づいて推測することで、コードをより迅速に理解することができます。
コードのコピー、変更、および保守が容易になります。
コーディング規約により、C# のベスト プラクティスがわかります。
名前付け規則
using ディレクティブが含まれていない簡単な例では、名前空間の修飾を使用します。 プロジェクトに名前空間が既定でインポートされていることがわかっている場合は、その名前空間の各名前を完全修飾する必要はありません。 次の例に示すように、修飾名が長すぎて 1 行に収まらない場合は、ドット (.) の後で改行できます。
var currentPerformanceCounterCategory = new System.Diagnostics. PerformanceCounterCategory();
他のガイドラインに合わせて、Visual Studio デザイナーのツールを使用して作成されたオブジェクトの名前を変更する必要はありません。
レイアウト規則
コードの構造を強調する書式が使用され、コードが読みやすくなっているのが、優れたレイアウトです。 マイクロソフトの例とサンプルは、次の規則に準拠しています。
コード エディターの既定の設定 (スマート インデント、4 文字インデント、タブを空白として保存) を使用します。 詳細については、「[オプション]、[テキスト エディター]、[C#]、[書式設定]」を参照してください。
1 つの行には 1 つのステートメントのみを記述します。
1 つの行には 1 つの宣言のみを記述します。
継続行にインデントが自動的に設定されない場合は、1 タブ ストップ (4 つの空白) 分のインデントを設定します。
メソッド定義とプロパティ定義の間に少なくとも 1 行の空白行を追加します。
次のコードに示すように、式に句を作成するときはかっこを使用します。
if ((val1 > val2) && (val1 > val3)) { // Take appropriate action. }
コメント規則
コメントは、コード行の末尾ではなく別の行に記述します。
コメントのテキストは大文字で開始します。
コメントのテキストはピリオドで終了します。
次の例に示すように、コメント デリミター (//) とコメント テキストの間に空白を 1 つ挿入します。
// The following declaration creates a query. It does not run // the query.
アスタリスクを整形したブロックでコメントを囲まないようにします。
言語ガイドライン
以降のセクションでは、コード例とサンプルを準備する際に C# チームが従っている方法について説明します。
文字列型 (String)
次のコードに示すように、短い文字列を連結するときは + 演算子を使用します。
string displayName = nameList[n].LastName + ", " + nameList[n].FirstName;
ループ内で文字列を追加する場合 (特に大量のテキストを処理する場合) は、StringBuilder オブジェクトを使用します。
var phrase = "lalalalalalalalalalalalalalalalalalalalalalalalalalalalalala"; var manyPhrases = new StringBuilder(); for (var i = 0; i < 10000; i++) { manyPhrases.Append(phrase); } //Console.WriteLine("tra" + manyPhrases);
暗黙的に型指定されるローカル変数
変数の型が代入の右側から明らかである場合、または厳密な型が重要でない場合は、ローカル変数の暗黙の型指定を使用します。
// When the type of a variable is clear from the context, use var // in the declaration. var var1 = "This is clearly a string."; var var2 = 27; var var3 = Convert.ToInt32(Console.ReadLine());
代入の右側から型が明らかではない場合は、var を使用しないでください。
// When the type of a variable is not clear from the context, use an // explicit type. int var4 = ExampleClass.ResultSoFar();
変数の型を指定するときに変数名に頼らないでください。 変数名が正しくない場合があります。
// Naming the following variable inputInt is misleading. // It is a string. var inputInt = Console.ReadLine(); Console.WriteLine(inputInt);
dynamic の代わりに var を使用しないようにしてください。
for ループおよび foreach ループでループ変数の型を決定するときは、暗黙の型指定を使用します。
次の例では、for ステートメントで暗黙の型指定を使用しています。
var syllable = "ha"; var laugh = ""; for (var i = 0; i < 10; i++) { laugh += syllable; Console.WriteLine(laugh); }
次の例では、foreach ステートメントで暗黙の型指定を使用しています。
foreach (var ch in laugh) { if (ch == 'h') Console.Write("H"); else Console.Write(ch); } Console.WriteLine();
Unsigned データ型
- 通常は、unsigned 型ではなく int を使用します。 C# では int を使用するのが一般的です。int を使用すると、他のライブラリと対話しやすくなります。
配列
宣言行で配列を初期化するときは簡潔な構文を使用します。
// Preferred syntax. Note that you cannot use var here instead of string[]. string[] vowels1 = { "a", "e", "i", "o", "u" }; // If you use explicit instantiation, you can use var. var vowels2 = new string[] { "a", "e", "i", "o", "u" }; // If you specify an array size, you must initialize the elements one at a time. var vowels3 = new string[5]; vowels3[0] = "a"; vowels3[1] = "e"; // And so on.
デリゲート
デリゲート型のインスタンスを作成するときは簡潔な構文を使用します。
// First, in class Program, define the delegate type and a method that // has a matching signature. // Define the type. public delegate void Del(string message); // Define a method that has a matching signature. public static void DelMethod(string str) { Console.WriteLine("DelMethod argument: {0}", str); }
// In the Main method, create an instance of Del. // Preferred: Create an instance of Del by using condensed syntax. Del exampleDel2 = DelMethod; // The following declaration uses the full syntax. Del exampleDel1 = new Del(DelMethod);
例外処理における try-catch ステートメントと using ステートメント
ほとんどの例外処理には、try-catch ステートメントを使用します。
static string GetValueFromArray(string[] array, int index) { try { return array[index]; } catch (System.IndexOutOfRangeException ex) { Console.WriteLine("Index is out of range: {0}", index); throw; } }
C# の using ステートメントを使用して、コードを簡潔にします。 try-finally ステートメントを使用するときに finally ブロックのコードが Dispose メソッドの呼び出しだけである場合は、using ステートメントを代わりに使用します。
// This try-finally statement only calls Dispose in the finally block. Font font1 = new Font("Arial", 10.0f); try { byte charset = font1.GdiCharSet; } finally { if (font1 != null) { ((IDisposable)font1).Dispose(); } } // You can do the same thing with a using statement. using (Font font2 = new Font("Arial", 10.0f)) { byte charset = font2.GdiCharSet; }
&& 演算子と || 演算子
例外を回避し、不要な比較を省いてパフォーマンスを向上させるには、次の例に示すように、比較を実行するときに && (& ではなく) および || (| ではなく) を使用します。
Console.Write("Enter a dividend: "); var dividend = Convert.ToInt32(Console.ReadLine()); Console.Write("Enter a divisor: "); var divisor = Convert.ToInt32(Console.ReadLine()); // If the divisor is 0, the second clause in the following condition // causes a run-time error. The && operator short circuits when the // first expression is false. That is, it does not evaluate the // second expression. The & operator evaluates both, and causes // a run-time error when divisor is 0. if ((divisor != 0) && (dividend / divisor > 0)) { Console.WriteLine("Quotient: {0}", dividend / divisor); } else { Console.WriteLine("Attempted division by 0 ends up here."); }
new 演算子
次の宣言に示すように、暗黙の型指定を使用してオブジェクトのインスタンス化を簡潔な形式にします。
var instance1 = new ExampleClass();
前の行は次の宣言に相当します。
ExampleClass instance2 = new ExampleClass();
オブジェクト初期化子を使用してオブジェクトの作成を簡略化します。
// Object initializer. var instance3 = new ExampleClass { Name = "Desktop", ID = 37414, Location = "Redmond", Age = 2.3 }; // Default constructor and assignment statements. var instance4 = new ExampleClass(); instance4.Name = "Desktop"; instance4.ID = 37414; instance4.Location = "Redmond"; instance4.Age = 2.3;
イベント処理
後で削除する必要のないイベント ハンドラーを定義する場合は、ラムダ式を使用します。
public Form2() { // You can use a lambda expression to define an event handler. this.Click += (s, e) => { MessageBox.Show( ((MouseEventArgs)e).Location.ToString()); }; }
// Using a lambda expression shortens the following traditional definition. public Form1() { this.Click += new EventHandler(Form1_Click); } void Form1_Click(object sender, EventArgs e) { MessageBox.Show(((MouseEventArgs)e).Location.ToString()); }
静的メンバー
- 静的メンバーは、クラス名 (ClassName.StaticMember) を使用して呼び出します。 こうすることで、静的アクセスが明確になり、コードがよりわかりやすくなります。 派生クラスの名前を持つ基本クラスに定義された静的メンバーを指定しないでください。 このコードをコンパイルすると、コードが読みやすくなくなり、派生クラスに同じ名前の静的メンバーを追加すると、将来的にコードが中断する場合があります。
LINQ クエリ
クエリ変数にはわかりやすい名前を使用します。 次の例では、シアトル在住の顧客に seattleCustomers を使用しています。
var seattleCustomers = from cust in customers where cust.City == "Seattle" select cust.Name;
エイリアスを使用して、匿名型のプロパティ名の大文字と小文字の使用が正しい Pascal 形式になるようにします。
var localDistributors = from customer in customers join distributor in distributors on customer.City equals distributor.City select new { Customer = customer, Distributor = distributor };
結果のプロパティ名があいまいになる場合は、プロパティ名を変更します。 たとえば、クエリで顧客名と販売店 ID を返す場合、クエリ結果で Name と ID をそのまま使用するのではなく、これらの名前を変更し、Name が顧客の名前であり、ID が販売店の ID であることを明確にします。
var localDistributors2 = from cust in customers join dist in distributors on cust.City equals dist.City select new { CustomerName = cust.Name, DistributorID = dist.ID };
クエリ変数と範囲変数の宣言で暗黙の型指定を使用します。
var seattleCustomers = from cust in customers where cust.City == "Seattle" select cust.Name;
前の例に示すように、クエリ句を from 句の下に配置します。
where 句を他のクエリ句より先に使用し、それ以降のクエリ句では、フィルター化されたデータセットが処理されるようにします。
var seattleCustomers2 = from cust in customers where cust.City == "Seattle" orderby cust.Name select cust;
内部コレクションにアクセスするときは、join 句ではなく複数の from 句を使用します。 たとえば、Student オブジェクトのコレクションがあり、各オブジェクトに試験の点数のコレクションが含まれているとします。 次のクエリを実行すると、90 点より高い点数とその点数を取った学生の姓が返されます。
// Use a compound from to access the inner sequence within each element. var scoreQuery = from student in students from score in student.Scores where score > 90 select new { Last = student.LastName, score };
セキュリティ
「安全なコーディングのガイドライン」のガイドラインに従います。