【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;
}

特にC#は言語仕様がそこまで複雑でないため識別子の種類によってCONSTANT 形式, snake形式を分けて考えたり区別する必要がそこまで無い事からこういう命名規則が使用されていないのと考えられます。

識別子の命名規則

.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) camel形式 Pascal形式 private const string message
フィールド(private以外) Pascal形式 camel形式 public int [ Tranform|transform ]
フィールド(private) camel形式 camel形式 private int transform
メソッド(private以外) Pascal形式 Pascal形式 public void Foo()
メソッド(private) camel形式 Pascal形式 private void [ foo()|Foo() ]
プロパティ(private以外) Pascal形式 camel形式 public int [ Count|count ] { get; }
プロパティ(private) 使わない 使わない ほぼ無意味なので使わない
イベント(private以外) Pascal形式 camel形式 publc event Action [ Clicked|clickd ]
イベント(private) 使わない 使わない ほぼ無意味なので使わない
パラメータ(メソッド引数) calem形式 calem形式 public Foo(int count)
ネームスペース Pascal形式 Pascal形式 namespace UnityEngine, System

「pribate以外」の表記は「public」、「protected」、「internal」、「protected internal」の4つを指します。つまり自分のクラス以外が見る可能性があるという意味です。

リストから分かるかと思いますが、Unity は private と public のアクセスレベルで命名規則が分かれていません。一方.NET標準ライブラリは private と public で明確に命名規則が分かれています。

Unityの方が規約が簡素なため覚えやすく簡単です。ただし、公開・非公開の区別が名前からできないため宣言元に飛んでを確認しないといけない場合があります。

Unity上で開発を行う場合、基本的にUnityの命名規則に従う方が良いと思いまが、Unityに依存しない汎用的なライブラリ類は.NET標準に寄せるなどの使い分けをしたほうがいいかもしれません。汎用アルゴリズムとしてgithub上にコードを公開する場合は.NET標準を使用したほうが良いでしょう。

一般的にUnity以外の世界では.NET標準の命名規則が広く用いられているため、UnityでC#を覚えた後に業務システム開発に参加すると命名規約が大きく異なり面食らう事になります。(これは私見ですが、多人数で作業する場合は.NET標準の命名規則を採用して公開・非公開を区別したほうが視認性が良くトラブルを若干ながら防止できると思います。

その他規約

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 だらけになり非表示うっとおしいです。ただ VisualStudio のデフォルト設定が this ありだったりするので警告だらけになったりします。使用するしないはプロジェクトによって異なると思いますが、.NET標準環境では使用する、Unityでは基本は使用しないが一般的だと思います。

但し特定のケース「引数とクラスメンバーが同じ場合thisを付ける」とか「継承元のクラスを明示的に指す必要があり base キーワードを使用する場合 this を明示しないと挙動が意図しないもになる」、「メソッドにnewキーワードを使用している」など、一部の場面で this が必要になるのでそういった場合だけ使用するのもアリです。

個人の場合は好きにしましょう。まぁ付けないと思います。

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

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

private Vector3 m_position;
private Transform m_transform;

基本的にUnityだとインスペクター上に表示するときは、「m」 とか先頭の「」は取り外してくれるしUnityEngine内でも使われまくっているので利用は自由です。但し使ってる理由がメンバー変数がたくさんあって分かりにくいとかだと少しクラスを分割したほうがいい事もあります。ちなみに.NET標準では非推奨としているので個人的には使用していません。

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

命名規則によっては使用しない方がいいです。

例えば、thisキーワードとすこぶる相性が悪いので例えば以下のように併用してしまうとめちゃくちゃ不細工なことになります。

private int _count = 10;

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

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

結局どうすればいいの?

個人の場合は好みで大丈夫です。何が良いという事はないです。ただし表記は統一しましょう。場所ごとに表記が違うのはダメです。

チームの場合はガイドラインを設けましょう。必ず。絶対に。ネット上にあるコーディング規約でJava由来のクソみたいなあまり良くないのが見つかりますがそれは採用しないようにしましょう。

参考資料

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/