c# MSDN クラス ライブラリ開発のデザイン ガイドラインまとめ

今回は
クラス ライブラリ開発のデザイン ガイドライン -MSDN
のMSDNドキュメントを読んでいきたいと思います。(主に命名規則周りを重点的に)

C#のドキュメントではありますが統一されたコーディング規則を
学ぶ、というのは言語問わず、役に立つと思います。

こちらの内容はC#の言語仕様にコーディング規則が
設定されているわけでなく、Microsoftで採用されている
ドキュメントやサンプルに用いられている規則をまとめたものです。

主にコーディングにおける命名規則を確認したければ項目2,3は
飛ばして読んでもいいと思います。(アセンブリ、DLL、名前空間に関する項目のため)

今回参照しているMSDNのドキュメントはクラスライブラリ作成者向けなので、
一般に公開するライブラリを作成するわけではなく、利用者としての開発者からすると、
少しだけすれ違いを感じる内容もあるかもしれませんが、統一された規則の
有用性を実感できればと思い、読んでみました。

コーディング規則のメリット

C# のコーディング規則 (C# プログラミング ガイド 参照)

  • コードの見た目が統一されるので、読みやすく内容に重点を置ける
  • コードを素早く理解出来る
  • コピー・変更、保守が容易になる
  • C#のベストプラクティスがわかる

名前に関するガイドライン

1. 大文字の使用規則

識別子が複数の単語で構成される場合アンダースコアやハイフンを単語の間に
使用しない(snake記法を推奨していない、ということですかね)

原則として

  1. 複数の単語で構成されるパブリックメンバー、型、名前空間の名前には
    Pascal記法を用いる
  2. パラメータ名にはCamel記法を用いる

これだけ。

  • Class名 Pascal
  • 列挙型名 Pascal
  • 列挙型値 Pascal
  • イベント Pascal
  • 例外クラス Pascal
  • readonlyのstaticフィールド Pascal
  • Interface名 最初に I をつけてPascal
  • メソッド Pascal
  • 名前空間 Pascal
  • パラメータ(引数の定義) Camel
  • プロパティ Pascal
  • privateなフィールド Camel

MSDNに挙げられている代表例はこんな感じ。
publicなフィールドは、非推奨のため載っておらず。
定数なんかに関しても載ってなかったけど、それは後ほど。

上記のみをざっくりと実践してみたコード

とりあえずprivateはcamel、publicはPascal(Interfaceだけ最初にIをつける)
とおぼえておけば大丈夫そうです。

識別子の単語に関しては更にルールが定められています。

  1. camel記法の先頭の単語を除き、2文字から成る頭字語の文字は共に大文字にする
    ex) DBRate, IOStream (Pascal)
  2. camel記法の先頭の単語を除き、3文字から成る頭字語では先頭のみ大文字にする
    ex) XmlWrite, HtmlReader (Pascal)

  3. camel記法の先頭の単語は、文字数関係なく大文字にしない
    ex) exmStream (camel)

※)全てのプログラミング言語が大文字と小文字を区別するわけではありませんので
全ての言語にこのルールを適用することは危険です。


2. アセンブリ・DLLの名前

アセンブリ DLL の名前には、System.Data のような、主要な機能を示す名前を選択します。 アセンブリ名や DLL 名が名前空間の名前に対応している必要はありませんが、アセンブリの名前を付ける場合は、名前空間の名前に従うのが妥当です。

MSDNでは次のような命名が紹介されています。

ということなので、例えば僕が作成したら

みたいな感じですかね。簡単簡単。たまーにKentaKomai.dllみたいなのもみかけますけどねw


3. 名前空間の名前

名前空間もアセンブリの命名規則と似たような感じです。以下の通り

名前空間名には、プリフィックスとして企業名を付け、各企業の名前空間の名前とプリフィックスが重複しないようにしてください。
名前空間の第 2 レベルには、バージョンに依存しない、安定した製品名を使用してください。
企業内のグループ名は変更されることが多いため、名前空間の階層構造での命名基準として組織の階層構造を使用することは避けてください。
名前空間名は長期的に使用する、不変の識別子です。 組織が発展する中で、組織にさまざまな変更があっても名前空間名が廃止されることはないようにしてください。


4. クラス・構造体・およびインターフェイスの名前

一般的に・・・

※一部抜粋

  1. Pascal 形式を使用して、名詞、名詞句、または場合によっては形容詞句で、クラス、インターフェイス、および値型に名前を付けます。
  2. クラス名には、プリフィックス (C など) を使用しないでください。
  3. 派生クラスの名前は、末尾に基本クラスの名前を付けるよう考慮します。 ex) FileStream extends Stream
  4. インターフェイス名には、その型がインターフェイスであることを示すために、プリフィックス I を付けます。
ジェネリック型パラメータの名前
  1. 1 文字の名前がそのパラメーター自体を完全に説明するものであり、説明的な名前によって付加価値を付けない場合を除き、ジェネリック型パラメーターには説明的な名前を付けます。
  2. 1 文字の型パラメーターを 1 つ持つ型の型パラメーター名として、T を使用するよう考慮します。
  3. 説明的な型パラメーター名には、プリフィックス T を付けます。
  4. パラメーターの名前で型パラメーターの制約を示すよう考慮します。 たとえば、ISession に制約されたパラメーターに TSession という名前を付けます。

これ読んで思ったのが、意外とジェネリック型パラメータって、クラスライブラリ書く、
って用途以外だと、案外書かないですよね・・・僕の場合・・・。

一般的な型の名前

結構限定的な内容も含まれますが、それ以外はPascal記法でわかりやすい単語を選択しましょう、と
いった、今までの内容と一貫した流れです。

  1. カスタム属性クラスには末尾にAttribute を追加します。
  2. イベントで使用する型 (C# のイベントの戻り値の型など) の名前には、末尾にEventHandler を追加します。
  3. イベント ハンドラーではないデリゲートの名前には、末尾にCallbackを追加します。
  4. デリゲートの識別子の末尾にDelegateを追加しないでください。
  5. System.EventArgs を拡張するクラスには、末尾にEventArgs を追加します。
  6. System.Enum クラスから派生しないでください。代わりに、使用している言語でサポートされているキーワードを使用します。 たとえば、C# の場合、Enum キーワードを使用します。
  7. System.Exception から継承した型には、末尾にException を追加します。(例外クラスは末尾にExceptionつける)
  8. System.Collections.IDictionary または System.Collections.Generic.IDictionary を実装する型には、サフィックス Dictionary を追加します。 System.Collections.IDictionary はコレクションの特定の型ですが、このガイドラインは下記の一般的なコレクションのガイドラインより優先されます。
  9. System.Collections.IEnumerable、System.Collections.ICollection、System.Collections.IList、System.Collections.Generic.IEnumerable、System.Collections.Generic.ICollection、または System.Collections.Generic.IList を実装する型には、末尾にCollection を追加します。
  10. System.IO.Stream から継承した型には、末尾にStreamを追加します。
  11. System.Security.CodeAccessPermission から継承した型、または System.Security.IPermission を実装する型には、末尾にPermissionを追加します。

自分で利用することがあるかは別として、.NET Framework利用してると、『あー・・・』と納得できるような
規約ばかりだと思います。.NETのライブラリはこの規約で書かれていますね。無意識でしたが、一貫されたルールが
あると、ライブラリ利用者・開発者は楽だ、というのが実感できます。

列挙値の名前
  1. 列挙値名にプリフィックスを使用しないでください。 たとえば、ADO 列挙値にプリフィックス ad を使用したり、リッチ テキスト列挙値にプリフィックス rtf を使用したりしないでください。
  2. 列挙型の名前の末尾にEnumを使用しないでください。
  3. flags列挙体の名前にFlagsを追加しないでください。
  4. 列挙体の値がビット フィールドでない場合は、列挙体には単数形の名前を使用します。
  5. 値としてビット フィールドを持つ列挙体 (flags 列挙体とも呼ばれます) には、複数形の名前を使用します。

なんかこの辺は、こうなってます!ってまんま載せただけになっちゃったけど、まぁ
こうなってますw


型メンバーの名前

個人的には、完璧にこの規約を守るっていうのは、一般的な日本人の英語の語彙だと
しんどくなることが多くなるかも、と少し感じますが、そこも含めてクリアできる
コーディング力を身につけたいものですね。

というわけで、ここが僕の中では本編

1. メソッドの名前

メソッド名には、動詞または動詞句を割り当てる

通常、メソッドはデータを操作するため、メソッドのアクションを表す動詞を使用すると、開発者にはメソッドの機能がよりわかりやすくなります。 メソッドが実行するアクションを定義するときは、開発者から見てわかりやすい名前を選択するように注意してください。 メソッドがアクションを実行する方法を表す動詞は使用しないでください。言い換えると、メソッド名には実装の詳細を使用しないでください。

2. プロパティの名前

プロパティの名前には、名詞、名詞句、または形容詞を使用する

Getメソッドと同じ名前のプロパティは使用しない

たとえば、プロパティに EmployeeRecord という名前を付け、またメソッドにも GetEmployeeRecord という名前を付けるということはしないでください。 開発者が各自のプログラミング タスクを実行する際にどのメンバーを使用したらいいかわからなくなるからです。

ブール型のプロパティの名前には、肯定的なフレーズを使用する。Is、Can、Has などのプリフィックスを付けることもできますが、これは有益な場合に限定する。

プロパティには、その型と同じ名前を付けるようにしてください。(列挙型限定?)

列挙型に厳密に型指定されたプロパティを使用する場合は、プロパティの名前を列挙型の名前と同じにできます。 たとえば、CacheLevel という名前の列挙型がある場合は、その値のいずれかを返すプロパティにも CacheLevel という名前を付けることができます。

3. イベントの名前

イベントの名前には、動詞、または動詞句を使用する

イベント名には、現在形と過去形を使用して、前後の概念を与える。ウィンドウを閉じる前に発生させるイベントにはClosing、ウィンドウを閉じた後に発生させる イベントにはClosedという名前を付ける。

プレイベントやポストイベントを表すために、Before または After というプリフィックスやサフィックスを使用しない。

イベントハンドラー(イベントの型として使用されるデリゲート)の名前にはEventHandlerというサフィックスを付ける。

イベントハンドラーシグネチャでは、senderおよびeという名前の 2 つのパラメーターを使用する。

4. フィールドの名前

フィールド名はPascal記法を使用する

フィールド名には名詞や名詞句を使用する

フィールド名にはプリフィックスを使用しない。 静的フィールドと非静的フィールドを区別するために、g_や s_を使用しない。


こんな感じ。とりあえず、メソッド・イベントには動詞・形容詞、プロパティ・フィールドには名詞、最低限
それだけでも覚えておけば、第一段階としてはいいと思います。

パラメータの名前

こちらも言うは易く行うは難し、で、ルールは少ないですが、万人に納得される名前、
となると、なかなか難しいです。

  1. パラメータ名はCamel記法を使用する
  2. パラメータ名には説明的な名前を使用する。パラメータ名と型を見ただけで使用法が判別できることが好ましい
  3. パラメータの型に基づくのではなく、意味に基づいた名前を使用する

こんな感じです。一部省略しましたが、だいたいの事に関するコーディング規則を
列挙できたかと思います。

MSDNの記事で取り上げられていない内容に関しては、基本的には使用頻度が極端に少ないか、
非推奨のものになっていると思われます。

特段、僕のほうからは言及できませんが、ここにない様々な要素のコーディング規約に関しても
国内外で議論されているようなので、僕が読んだ中でいくつか紹介しておきたいと思います。

 

追記 2014/04/28

オブジェクト倶楽部、コーディング規約の会の「C# コーディング標準」の駄目なところ

 

ちょっと、この記事の内容からは外れるものも含まれますが、勉強になりました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です