| 公開 | 2009-03-07 |
| 更新 | 2011-04-08 |
私の C# コーディングについての覚え書きです。何かの参考になれば幸いです。
まずは、.NET Framework ドキュメントの Guidelines for Names などを読んで実践しましょう。その上で、さらに“分かり易い”コードを書くためには、どんな工夫があるでしょうか。
コメントの内容は、ピリオド(句点)で終わる「説明文」にします。なるべく体言止めにはしません。(体言止めでは説明不足になってしまう嫌いがあるように思います。)
// ○○のために○○する。
...;
また、メソッド内部の一行コメントでは、“そのコメントが及ぶ範囲”に留意します。通常は直後のブロックについてのコメントです。意味のある塊を分けるべく空行を入れてブロックを分割します。
// このブロックのコメント。
...;
...;
...;
// 上記コメントは、このブロックには及ばない。
...;
...;
...;
必要であればブロックを {..} で括ってしまいます。
// このブロックのコメント。
{
...;
...;
...;
...;
...;
...;
}
コメントを書くために空行を入れている、という感じになります。そのブロックに簡潔なコメントを(実際に書くかどうかは別として)書けるかどうか、が空行を入れる基準になります。
C# 3.0 から、変数宣言のキーワード var が導入されました。これにより、変数宣言から“自明である型の記述”を省略できます。
int x = 123;
Unit y = new Unit();
var x = 123;
var y = new Unit();
var は LINQ を実現するために追加された構文の一つですが、LINQ の使用如何にかかわらず、全ての場面で使用できます。(CLR 2.0 でも使えます。)特に理由がない限り(後述)、変数は var で宣言・初期化しています。
※var を積極的に使用する理由についてのご質問があったので追記です。
LINQ に限らず var を積極的に使用する理由としては、次の 3 点が挙げられます。
特に 3 番目の理由について、「変数の型は、その名称と使い方によって明示される。本来的に必要な宣言ではない」との発想があります。「型推論」の背景をなす発想です。
従来の変数宣言には、「変数を宣言する」効果と同時に「変数の型を明示する」効果もあります。
しかし変数の宣言で重要なのは、その型よりも名称です。たとえば、Windows API を利用する C/C++ 言語では「変数名に型名のプリフィックスを付ける」という命名の習慣(システムハンガリアン)もありますが、これは C# では推奨されません。変数宣言において、その厳密な型名は、あまり重要ではないのです。(ポリモーフィズム。具象クラスの型名は、そのインスタンスを格納する変数にとっては関心の対象外であるべき。)
一方で「過剰な var の使用は良いスタイルではない(型を明示すべきだ)」との意見もあり得ます。変数宣言における型名の有無がコードの可読性に及ぼす影響については議論の余地がありそうです。
参照型の変数を null で初期化したいときもあります。この場合、そのままでは var は使えません。null、だけでは型を推論しようがないためです。
var unit = null; // Compile Error!
何らかの形で型を示す必要があります。こういうときは default(T) キーワードで型を明示します。
var unit = default(Unit);
※あるいは var x = null as T; でも同様に宣言できますが、まあ default が無難でしょう。(出力される中間コードに違いはない。)
ちなみに default は参照型だけでなく値型でも有効です。
var を意図的に使わない場面もあります。メソッドの out 引数を受け取るための変数の宣言には var を使いません。
Unit unit;
if (!units.TryGetValue(key, out unit))
{
...
}
値の初期化(右辺)を書かないことで、その変数が“out 引数を受信するためにある”ことを示唆します。(通常は、このような変数宣言は推奨されない=警告が出るために区別が可能。)
総称 [generics] 型を作る際に、default(T) キーワードを使うことがあります。型パラメーター T が参照型であれば null を、値型であれば初期値(通常は 0)を意味します。
このキーワードは通常の型に対しても使用できます。通常の場面でも積極的に使ってみましょう。
たとえば、メソッドのパラメーターの引数に null を渡す際には、ただ null とだけ書くよりは、default キーワードで型を記述する方が分かり易いように思います。
var message = String.Format(null, format, items.Count);
throw new ObjectDisposedException(null);
var message = String.Format(default(IFormatProvider), format, items.Count);
throw new ObjectDisposedException(default(string));
クラスのフィールドやメソッドの宣言の順序には、特に規定はありません。基本的には自由な順番で記述できます。ただ、やはり一貫性は必要です。何らかのルールを設けることになるでしょう。
私は以下の順序で宣言しています。
各項目は #region ディレクティブで括ります。項目内では、公開するもの(public, internal, protected)を上に、非公開のもの(private)を下に置きます。
流石に「アルファベット順に並べる」というようなことはする必要はないでしょう。統合開発環境(IDE)が並べて表示してくれます。しかし「フィールドやメソッドが何のルールもなく適当な順序で入り乱れている」というのでは、保守しにくいコードになってしまうように思います。
StyleCop のコーディングスタイルでは、以下の順序で定義されます。基本的な考え方は同じでしたが、Static を先に書いたり、Fields の次に Constructors を書くようになっています。
partial キーワードを使うと、一つのクラスを複数のソースコードファイルに分割して記述することができます。
public partial class Item
{
public void Method1()
{
...
}
}
partial class Item
{
public void Method2()
{
...
}
}
この機能は、主に IDE が UI のデザインのコードとロジックのコードを分離するために用いるものです。
partial は、プログラマーが自前でコードを分割するためにも使えます。たとえば、IDisposalbe を実装するクラスを作る際に、IDisposalbe 関連のフィールドやメソッドだけを抽出して T.IDisposable.cs ファイルに分離する、といった使い方が考えられます。
public partial class NativeResource
{
#region Fields
private bool disposed;
#endregion
#region Destructor
~NativeResource()
{
...
}
#endregion
#region Methods
public void Dispose()
{
...
}
protected virtual void Dispose(bool disposing)
{
...
}
protected void AssertNotDisposed()
{
...
}
#endregion
}
非常に細かいことですが、次のコードは、
if (string.IsNullOrEmpty(source))
{
...
}
こう書きたいです。
if (String.IsNullOrEmpty(source))
{
...
}
"string" は、C# のキーワードです。毎回、System.String だとか System.Int32 などと書くのは面倒なために、基本型については、対応するキーワードが言語側に用意されている訳です。
ただ、「キーワードは、飽くまで便宜のための構文糖であり、本来は型の名前にメソッドを続ける」との発想から、私は下の書き方をします。……まあ、好みの問題ですね。
try-catch で特定の例外について捕捉する場合、例外クラスの名前空間は、あえて省略せずに記述します。
try
{
...
}
catch (System.ArgumentException)
{
...
}
catch (System.OutOfMemoryException)
{
...
}
catch (System.IO.IOException)
{
...
}
なぜ(名前空間を using しているにもかかわらず)フルネームで記述するのか。例外の型については、常に階層構造を意識したいと思うのです。catch を並べるときには特に。