C#コードをフォーマットする正しい方法は1つではないかもしれませんが、チーム全体で一貫したスタイルに合意することで、よりクリーンで読みやすく、スケーラブルなコードベースにすることができます。よく整理されたスタイルガイドは、最終的な製品にまとまりを持たせるために、矛盾を抑えるのに役立つ。このページでは、独自のスタイルガイドを作成する際に、命名規則やコードの書式について留意すべきヒントや主な注意点を紹介します。
注:ここで紹介する推奨事項は、マイクロソフトが提供するものである。最良のコードスタイルガイドのルールとは、あなたのチームのニーズに最も適したものである。
コードスタイルガイドの例はこちらでご覧いただけます。また、完全版の電子書籍(C#スタイルガイドを作成する)をダウンロードすることもできます: をスケールアップする、よりクリーンなコードを書く。
C#は識別子を区切るのにスペースを使うので、変数名にスペースを入れて定義することはできない。ケーシング・スキームは、ソースコード中で複合語名や語句を使わなければならない問題を軽減することができる。
以下に、よく知られた命名規則とケーシング規則をいくつか挙げる:
キャメルケース
キャメルキャップとしても知られるキャメルケースとは、スペースや句読点を入れず、大文字1文字で単語を区切ってフレーズを書く慣習のこと。最初の文字は小文字である。
通常、ローカル変数とメソッド・パラメーターはキャメルケースで表示される。例:
examplePlayerController
maxHealthPoints
endOfFile
パスカル・ケース
パスカル・ケースはキャメル・ケースのバリエーションで、頭文字が大文字になる。Unityの開発でクラス名やメソッド名に使用します。パブリック・フィールドもパスカル・ケースにすることができる。例:
ExamplePlayerController
MaxHealthPoints
EndOfFile
スネークケース
この場合、単語間のスペースはアンダースコア文字に置き換えられる。例:
example_player_controller
max_health_points
end_of_file
ケバブケース
ここでは、単語間のスペースはダッシュに置き換えられている。そして、ダッシュ文字の「串」のようなものの上に単語が表示される。例:
example-player-controller
最大ヘルスポイント
エンドオブファイル
ケバブ・ケースの問題は、多くのプログラミング言語がダッシュをマイナス記号として使っていることだ。さらに、ダッシュで区切られた数字をカレンダーの日付として解釈する言語もある。
ハンガリー表記法
変数名や関数名は、その意図や型を示すことが多い。例:
int iCounter
string strPlayerName
ハンガリー語表記は古い慣習であり、Unityの開発では一般的ではありません。
変数とフィールドについては、以下のルールを考慮してください:
- 変数名には名詞を使う:変数名は、特定の物事や状態を表すので、明確で説明的でなければならない。変数がbool型(下記参照)である場合を除き、命名には名詞を使用する。
- ブール語の前に動詞を付ける:これらの変数は真か偽の値を示す。というような質問に対する答えであることが多い:選手は走っているか?試合は終わったのか?
- 動詞を前につけて、意味をより明確にする。多くの場合、これは説明や条件(isDead、isWalking、hasDamageMultiplierなど)と対になっている。
- 意味のある名前を使う。略さないこと(数学でない限り):変数名はその意図を明らかにする。発音しやすく、検索しやすい名前を選ぶ。
- ループや計算式では1文字の変数でも問題ありませんが、それ以外の状況では省略しないでください。いくつかの母音を省略することで節約できる時間よりも、明瞭さの方が重要なのだ。
- 素早くプロトタイプを作るには、一時的に短い「ジャンク」な名前を使い、後でもっと意味のある名前にリファクタリングすればいい。
- パブリック・フィールドにはパスカル・ケースを使い、プライベート変数にはキャメル・ケースを使う:パブリック・フィールドに代わるものとして、パブリックな "ゲッター "を持つプロパティを使用します(前節と後節を参照)。
- 接頭辞が多すぎたり、特殊なエンコーディングは避ける:ローカル変数と区別するために、プライベート・メンバー変数の前にアンダースコア (_) を付けることができます。
- あるいは、メンバ変数とローカル変数を文脈で区別するために this キーワードを使い、接頭辞を省略することもできます。パブリック・フィールドとプロパティは通常接頭辞を持ちません。
- スタイル・ガイドによっては、プライベートなメンバ変数(m_)、定数(k_)、静的変数(s_)に接頭辞を使用することで、変数名が一目でその変数に関する詳細がわかるようにしています。
- 多くの開発者はこれらを避け、代わりにエディターに頼っている。しかし、すべてのIDEがハイライトや色分けをサポートしているわけではなく、リッチコンテキストをまったく表示できないツールもある。チームとしてどのように接頭辞を適用するか(あるいは適用するかどうか)を決定する際には、この点を考慮してください。
- アクセスレベル修飾子を一貫して指定する(または省略する):アクセス修飾子を省略すると、コンパイラーはアクセス・レベルをprivateとみなす。これはうまくいくが、デフォルトのアクセス修飾子を省略する方法には一貫性を持たせよう。
- 後でこれをサブクラスで使いたい場合は、protectedを使う必要があることを覚えておいてほしい。
列挙型は、名前付き定数の集合によって定義される特殊な値型である。デフォルトでは、定数はゼロから始まる整数である。
列挙型の名前と値にはパスカル・ケースを使用する。パブリックな列挙型をクラスの外部に置くことで、それらをグローバルにすることができる。列挙名には単数名詞を使用する。
注:でマークされたビット単位の列挙型。 属性でマークされたビット単位の列挙型は、この規則の例外である。複数のタイプを表すため、通常は複数形にする。
クラスやインターフェースの名前をつけるときは、以下の標準的なルールに従ってください:
クラス名にはパスカル・ケースの名詞を使う:そうすることで、クラスを整理することができる。
ファイル内にMonoBehaviourがある場合、ソースファイル名が一致していなければなりません:ファイル内に他の内部クラスがあるかもしれませんが、MonoBehaviourは1ファイルにつき1つだけ存在するようにしてください。
インターフェイス名の前に大文字の "I "を付ける: その後に、機能性を表す形容詞を続ける。
C#では、実行される命令はすべてメソッドのコンテキスト内で実行される。
メソッドはアクションを実行するので、これらのルールを適用して適切な名前を付ける:
名前を動詞で始める: 必要に応じてコンテキストを追加する(GetDirection、FindTargetなど)。
パラメータにはキャメルケースを使用する: メソッドに渡されるパラメータをローカル変数のようにフォーマットする。
boolを返すメソッドは質問をする: ブール変数そのものと同じように、メソッドが真偽の条件を返す場合は動詞をプレフィックスとしてつけます。IsGameOver、HasStartedTurnなど)。
注:Unityの開発では、"ファンクション "と "メソッド "という言葉はしばしば同じ意味で使われます。しかし、C#ではクラスに組み込まずに関数を書くことはできないので、「メソッド」というのが正しい呼び方である。
C#のイベントはオブザーバー・パターンを実装しています。このソフトウェアデザインパターンは、1つのオブジェクトであるサブジェクト(またはパブリッシャー)が、オブザーバー(またはサブスクライバー)と呼ばれる依存オブジェクトのリストに通知できる関係を定義します。このように、主体は、関係するオブジェクトを緊密に結合させることなく、オブザーバーに状態変化をブロードキャストすることができる。
被写体やオブザーバーにおけるイベントやそれに関連するメソッドには、いくつかの命名法が存在する。以下のセクションの実践を試してみてください。
動詞のフレーズでイベントの名前を付ける。状態の変化を正確に伝えるものを選ぶようにしましょう。
現在分詞または過去分詞を使って、出来事の前後の状態を示す。例えば、ドアを開ける前のイベントには "OpeningDoor "を、開けた後のイベントには "DoorOpened "を指定する。
イベントにはSystem.Actionデリゲートを使用します。ほとんどの場合 Action<T>デリゲートはゲームプレイに必要なイベントを処理できる。
戻り値の型はvoidで、異なる型の入力パラメータを16個まで渡すことができる。定義済みのデリゲートを使えば、コードを節約できる。
注:また イベントハンドラまたは EventHandler<TEventArgs>のデリゲートを使うこともできる。全員がどのようにイベントを実施すべきか、チームとして合意する。
件名の)イベント提起方法の前に "On "を付ける。イベントを呼び出すサブジェクトは、通常、"On "の接頭辞が付いたメソッド(例えば、"OnOpeningDoor "または "OnDoorOpened")から呼び出す。
(オブザーバー内の)イベント処理メソッドの前に、対象の名前とアンダースコア(_)を付ける。オブジェクトの名前が "GameEvents "であれば、オブザーバーは "GameEvents_OpeningDoor "または "GameEvents_DoorOpened "というメソッドを持つことができる。
チーム内で一貫したネーミング・スキームを決め、スタイル・ガイドにそのルールを導入する。
注:この「イベント処理メソッド」は、EventHandlerデリゲートと混同してはならない。
必要な場合のみ、カスタムEventArgsを作成する。イベントにカスタムデータを渡す必要がある場合は、EventArgsの新しいタイプを作成します。 から継承するかから継承するか、カスタム構造体から作成します。
名前空間を使用して、クラス、インターフェース、列挙型などが、他の名前空間やグローバル名前空間に存在するものと衝突しないようにします。名前空間は、Unity Asset Storeのサードパーティ製アセットや、プロジェクトの最終バージョンには含まれない他のテストシーンとの競合を防ぐこともできます。
名前空間を適用する場合
特殊記号やアンダースコアのないパスカルケースを使用する。
名前空間接頭辞の繰り返し入力を避けるために、ファイルの先頭にusingディレクティブを追加する。
サブネームスペースも作成する。ドット(.)演算子を使用して名前のレベルを区切ることで、スクリプトを階層的なカテゴリに整理することができます。例えば、"MyApplication.GameFlow"、"MyApplication.AI"、"MyApplication.UI "などを作成し、ゲームの異なる論理コンポーネントを保持することができます。
コードでは、これらのクラスをそれぞれEnemy.Controller1、Enemy.Controller2と呼ぶ。接頭辞の入力を省くためにusing行を追加する(例:Enemy;を使う)。
コンパイラはController1とController2というクラス名を見つけると、Enemy.Controller1とEnemy.Controller2という意味だと理解する。
スクリプトが異なる名前空間から同じ名前のクラスを参照する必要がある場合は、接頭辞を使用してそれらを区別します。例えば、Player名前空間にController1クラスとController2クラスがある場合、Player.Controller 1とPlayer.Controller2と記述することで、競合を避けることができます。そうでない場合、コンパイラーはエラーを報告する。
コードスタイルのヒント
一般的なフォーマットの詳細については、こちらをご覧ください。コードスタイルガイドの例もご覧ください。