【C#】Unityと.NET標準ライブラリの命名規則の違い

.NET標準は「System名前空間内にあるクラス類」を指します。一方のUnityは「UnityEngine名前空間内にあるクラス類」以下にあるオブジェクト群を指します。それぞれ同じC#言語ですが各々の間で大きく命名規則が異なっています。という訳でちょっとまとめてみました。

命名規則の種類

命名規則にはいくつか代表的な形式があります。代表的な形式を以下に挙げます。

Item Description e.g.
Pascal 形式 先頭が大文字で後は小文字 "ItemList", "GameControlelr"
camel 形式 先頭が小文字で語句ごとに大文字 "itemList", "gameController"
snake(スネーク) 形式 全部小文字、語句をアンダースコアでつなぐ "item_list", "game_controller"
CONSTANT 形式 全部大文字、語句をアンダースコアでつなぐ "ITEM_LSIT, "GAME_CONTROLLER"

C#では(というか古くはMSの推奨として)、「snake 形式」と「CONSTANT 形式」は使用しません。従って、他言語では見かけることもある定数を「CONSTANT 形式」で宣言といった文化はありません。enumのメンバーも同様です。

public static class Cosntant
{
    // こういう命名規則は使用しない
    public const int ERROR_CODE = -1;

    // 一般的にこうする
    public const int ErrorCode = -1;
}

最近はIDE上で定数は特別な色で表示されるシーンも多いため命名規則で区別しないでも大丈夫みたいな側面はあると思います。個人的にはそこまで困ったことないですね。

識別子の命名規則

.NET標準とUnityの命名規則の違いを以下にまとめてみました。

種類 .NET標準 Unity e.g
クラス・構造体 Pascal形式 Pascal形式 class Sample { ...
抽象クラス Pascal形式 Pascal形式 abstract class Sample { ...
インターフェース Pascal形式 Pascal形式 interfalce class Sample { ...
列挙型(宣言) Pascal形式 Pascal形式 enum Color { ...
列挙型(メンバー) Pascal形式 Pascal形式 enum Color { Red, Blue...
デリゲート Pascal形式 Pascal形式 delegate void Foo(int, int)
定数(private以外) Pascal形式 Pascal形式 public const string Message
定数(private) Pascal形式 Pascal形式 private const string message
フィールド(private以外) 使わないで camel形式 public int transform
フィールド(private) _camel形式 (*1) _camel形式 (*2) private int [ _transform | m_transform ]
メソッド(private以外) Pascal形式 Pascal形式 public void Foo()
メソッド(private) Pascal形式 Pascal形式 private void Foo()
プロパティ(private以外) Pascal形式 camel形式 public int [ Count|count ] { get; }
プロパティ(private) calem形式 不明 あまり使わない
イベント(private以外) Pascal形式 camel形式 publc event Action [ Clicked|clickd ]
イベント(private) calem形式 不明 滅多に使わない
パラメータ(メソッド引数) calem形式 calem形式 public Foo(int count)
ネームスペース Pascal形式 Pascal形式 namespace UnityEngine, System
  • (*1) 以前からアンダースコアつけるべしでしたが最近スタティックには「s_」, スレッドは「t_」などが追加されて議論を呼んでいしたね。
  • (*2) 「m_」だったり「_」だったり形式は色々あるみたいです

「private以外」の表記は「public」「protected」「internal」「protected internal」「private protected(C#7.2から追加)」の4つを指します。つまり自クラス外に可視性があることを指しています。

リストから分かるかと思いますが、ほぼ Pascal 形式で Unity と .NET での違いは外部公開するフィールドとプロパティくらいです。

この命名規則ですが、private なプロパティとか同じクラスにある常数が Pascal 形式で見分けがつかないのが少し気になります。ただ、最近は IDE が種類ごとに細かく色を付けてくれるので完全に識別不能ではないと思います。

Unity 上で開発を行う場合、基本的にUnityの命名規則に従う方が良いと思いまが、Unityに依存しない汎用的なライブラリ類は.NET標準に寄せるなどの使い分けをしたほうがいいかもしれません。汎用アルゴリズムとしてgithub上にコードを公開する場合は .NET の規約に従ったほうが受け入れられやすいと思います。外部公開のプロパティが小文字のライブラリとか Unity のライブラリ以外で見た事がありません。

その他の規約や書き方

publicフィールドの扱い

Unity では変数をインスペクター上に表示するために public で宣言する事がありますが、やはりインスペクター以外の他のクラスから自由に書き換えできるのでできれば避けたいところです。

// Sample.cs
using UnityEngine;

public class Sample : MonoBehaviour
{
    public Vector3 offset; // インスペクター上で編集したい
}

文字数が多くなって面倒ですが(多人数で作業する場合特に)予期せず書き換えられて自分のクラスの処理(Updateなど)が失敗してしまう事もあり外から書き換えてほしくない場合は、最近は以下のように宣言します。

// Sample.cs
using UnityEngine;

public class Sample : MonoBehaviour
{
    // インスペクター上から編集できるが他のクラスからは見えなくなる
    [SerializeField] private Vector3 offset;
}

また、他のクラスから値を確認したい場合プロパティを経由して値の取得だけできるようにします。

// Sample.cs
using UnityEngine;

public class Sample : MonoBehaviour
{
    [SerializeField] private Vector3 offset;

    // (1) C# 6.0以前のプロパティ書き方(= Unity2018.3以前)
    public Vector3 Offset { get { return this.offset; } }

    // (2) C# 6.0以降の書き方 (= Unity2018.3以降)
    public Vector3 Offset => this.offset;
}

// 短く記述可能なので(2)がおすすめ

インスペクター上に表示しつつ読み書きしたい場合、以下のように記述します。

// Sample.cs
using UnityEngine;

public class Sample : MonoBehaviour
{
    [SerializeField] private Vector3 offset;

    // (1) C# 6.0以前のプロパティ書き方
    public Vector3 Offset
    {
        get { return this.offset; }
        set // 値の設定用のプロパティ宣言
        {
            if(value.x <= 2.0f)
            {
                return; // ★ある数値の場合は設定しないなどの値のチェックができる
            }
            this.offset = value;
        }
    }

    // ★(2) C#7.0 の書き方(get/set指定はC# 7.0が必要)
    // ★単純な値の出し入れなら短く書ける
    public Vector3 Offset { get => this.offset; set => this.offset = value; }

    public Vector3 Offset
    {
        get => this.offset; // ★getだけラムダ式で書くこともできる
        set
        {
            // ★長い場合普通の書き方ができる
            if(value.x <= 2.0f)
            {
                return;
            }
            this.offset = value;
        }
    }
}

thisキーワードの有無

クラスのメンバー指すときに使用する this キーワードですが基本は付けません。

.NET標準 Unity
つけない つけない

実際付け始めると this だらけになると視認性が低下します。(VS の設定はすごく昔は this ありだったような気がしますが(?)引きずって this まみれになってたりするのをたまに見かけます)this キーワードを使用するしないはプロジェクトによって異なると思いますが、基本使用しないと思います(this を使用しない場合、自分のクラスの static メンバーとインスタンスメンバーの区別がつかなくなりますがそれが問題になる事は殆どありません)

特定のケース「引数とクラスのフィールド名が同じ場合 this を付ける」とか「継承元のクラスを明示的に指す必要があり base キーワードを使用する時に this を明示したい」、「メソッドにnew キーワードを使用しているメソッドを base と区別するために明示する」など、一部の場面で base やパラメータと区別するために this が必要になるのでそういった場合 this が必要になります。

個人の場合は好きにしましょう。まぁホビーユースなら面倒なので付けないと思います。

フィールドメンバーの先頭にm_, s_

割と良くあると思いますが以下のような感じです。

// Unity
private Vector3 m_position;
private Transform m_transform;

// .NET
private float _value; // 基本的にアンダースコアを付ける
private static float s_value; // static は先頭に s_

基本的にUnityだとインスペクター上に表示するときは、「m_」 とか先頭の「_(アンダースコア)」は取り外してくれるし UnityEngine 内では使われまくっているので事実上標準です。但し使ってる理由が「メンバー変数がたくさんあって分類するため」だと少し考えちゃいますね。クラスの設計自体がインスペクターの表示に影響を受けることがあるため善し悪しです。

変数名の先頭にアンダースコア

前述の「m_」の事もありますが、これはプロジェクトや個人のポリシーで使用するか決めたほうがいいと思います。

.NET だと先頭に「s_」、「t_」を付けろだとか言っていますがまぁ慣れていないと気持ち悪い、他のプロジェクトと整合が取れない個人の分類法に反するなど色々あると思うので。

但し、プレフィックスは、this キーワードとすこぶる相性が悪いので例えば以下のように併用してしまうとめちゃくちゃです。

private int _count = 10;

public void Foo()
{
    this._count = 20; // thisと併用すると見た目が意味不明になる
}

こういうケースが発生しないように規約は調整する必要があります。

結局どうすればいいの?

他人に公開するつもりのあるコードはファイル先頭に以下を宣言します。

#pragma warning disable // コード内の警告を全て抑制する

// もしくは

#if RELEASE
#pragma warning disable
#endif

という冗談はさておき、特殊な規約を採用しているプロジェクトのコードが自分のプロジェクトに取り込まれた時にめちゃくちゃ警告が出るのは予防できそうですtが。

まぁでも規約は規約なので、守るかかもらないか、スタイルをどうするかは個人の場合は好みで決めて大丈夫です。何が良いという事はないです。

ただ自分の決めたポリシーと既存のコードの規約が違う場合に、Githubの規約にも記載ありましたが他人のコードの方を無理に直そうとするのはやめた方がいいです。普通に時間の無駄 or 反感を買うだけなので既存のスタイルがあるならそ少なくともそのファイル内はそのスタイルを踏襲して表記を統一しましょう。いくつか書き方の引き出しのセットがあって切り替えてくイメージです。

ちなみにゼロから開発するときにプロジェクト内の場所ごとに表記が違うのNGです。チームの場合はガイドラインを設けましょう。必ず。絶対に。ネット上にあるコーディング規約でJava由来のクソみたいなあまり良くないのが見つかりますがそれは採用してはいけません。

規約を決めたら CodeFX や Lint に規約を設定してツールで逐次チェックしているのが安いです(設定は大変だと思いますが最終的に安いです)

参考資料

MSDN、「名前付けガイドライン」:

https://docs.microsoft.com/ja-jp/dotnet/standard/design-guidelines/naming-guidelines

Unityの命名規則のフォーラム:

https://forum.unity.com/threads/c-naming-conventions-for-unity.135617/

.NET Core のコーディングガイドライン

https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/coding-style.md