Unityのプロパティをもっとスッキリ書く![field: SerializeField]の使い方

広告

はじめに

Unityでスクリプトを書いていると、こんなコードを見かけることがあります。

public float LifeMax
{
    get
    {
        return lifeMax;
    }
}

[SerializeField]
private float lifeMax = 10;

「なんかごちゃごちゃしているな…」と感じませんでしたか?

実はこれ、もっとシンプルに書けます。この記事では、なぜこのような書き方になっているのかを理解した上で、スッキリと書き直す方法を解説します。


そもそも、なぜこんな書き方をするの?

プロパティとフィールドの違い

まず前提知識として、C# には フィールド と プロパティ という2種類のメンバーがあります。

種類書き方の例特徴
フィールドpublic float lifeMax;シンプルだが、読み取り専用にしにくい
プロパティpublic float LifeMax { get; }get / set で細かく制御できる

プロパティを使う主な理由は、「外からは読めるけど、書き換えはクラスの中だけ」 という制御をしたいからです。

たとえば、HPの最大値は外部から勝手に変更されると困りますよね。そこで次のように書きます。

// 外から読み取りはできる(public get)
// でも書き換えはこのクラスの中だけ(private set)
public float LifeMax { get; private set; }

Inspectorに表示したい&外から変更させたくない、という矛盾

Unityでは [SerializeField] を使うと、private なフィールドでも Inspectorに表示 できます。

しかし困ったことに、プロパティには [SerializeField] が直接使えません(正確には、自動プロパティのバッキングフィールドに適用できなかった)。

そのため、昔は次のように プロパティ + プライベートフィールド の2つをセットで書く必要がありました。

// Inspector表示用のプライベートフィールド
[SerializeField]
private float lifeMax = 10;

// 外部公開用のプロパティ(フィールドをラップしているだけ)
public float LifeMax
{
    get
    {
        return lifeMax;
    }
}

これが冒頭のコードの正体です。やりたいことは1つなのに、書くものが2つ必要という少し不便な状態でした。


スッキリ書き直してみよう

C# 7.3 以降では、[field: SerializeField] という書き方が使えるようになりました。

[field: SerializeField]
public float LifeMax { get; private set; } = 10;

これだけです!たった1行で、先ほどのコード全体と同じ意味になります。

何が変わったの?

[field: ...] という書き方は、「この属性をバッキングフィールドに適用する」 という指示です。

自動プロパティ({ get; private set; } のような書き方)は、C# が内部で自動的にフィールドを生成してくれています。そのフィールドのことを バッキングフィールド と呼びます。

// 自動プロパティを書くと、C#が内部でこんなフィールドを自動生成している(イメージ)
private float <LifeMax>k__BackingField;

[field: SerializeField] は、その自動生成されたフィールドに [SerializeField] を付けてね、と伝える構文です。


並べて比較してみよう

書き換え前

[SerializeField]
private float lifeMax = 10;

public float LifeMax
{
    get
    {
        return lifeMax;
    }
}
  • 行数:8行
  • フィールドとプロパティの 2つを管理 する必要がある
  • 変数名が lifeMax と LifeMax の2つある(命名を揃える手間もある)

書き換え後

[field: SerializeField]
public float LifeMax { get; private set; } = 10;
  • 行数:2行
  • 管理するのは プロパティ1つだけ
  • 変数名は LifeMax の1つだけ

Inspector表示の確認

実際にUnityエディタ上でどう見えるかも確認しておきましょう。

[field: SerializeField] を使った場合、Inspectorには次のように表示されます。

Life Max    10

ポイント:フィールド名ではなくプロパティ名(LifeMax)が表示されます。Unity側が自動的に LifeMax → Life Max のように変換します。


注意点

Unity 2020.1 以降が対象

[field: SerializeField] が正しく動作するのは Unity 2020.1 以降 です。それ以前のバージョンを使っている場合は、従来の書き方を続けてください。

set を完全に省略すると初期値を設定できない

// NG:初期値を代入できないためコンパイルエラー
[field: SerializeField]
public float LifeMax { get; } = 10; // これはOK(コンストラクタから代入可)

readonly 相当にしたい場合

完全に外から書き換えを禁止したい(コンストラクタからのみ設定)場合は { get; } のみでも問題ありません。

[field: SerializeField]
public float LifeMax { get; } = 10;

まとめ

項目従来の書き方新しい書き方
行数多い少ない
管理するメンバー数フィールド + プロパティプロパティのみ
Inspector表示
外部からの書き換え制限

[field: SerializeField] を使うと、コードが読みやすくなり、管理するものも減ります。「フィールドとプロパティの2つを同期しないと…」という心配も不要になります。

ぜひ今書いているスクリプトから少しずつ取り入れてみてください!


訪問数 16 回, 今日の訪問数 16回

広告

Unity

Posted by hidepon