はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】プロパティをインスペクターに表示するために[field: SerializeField]を利用していても[FormerlySerializedAs]でリネーム対応できる

はじめに

以前からプロパティでも[field: SerializeField]と記述することでインスペクターに表示できることは知っていました。

public class Sandbox : MonoBehaviour
{
    [field: SerializeField] 
    public float Value { get; private set; }
}
インスペクターに表示されている様子

個人的に利用しようとはあまり思わなかったのですが、そういえばFormerlySerializedAsAttributeを利用してリネームにも対応できるのかなと気になり調べてみました。というのも以下の記事を読んでいて、名前を変更した時に値が引き継げないと記述されていて本当だろうかと疑問に思ったからです。

takap-tech.com


結論可能だったのですが、それらを含めて分かったことをまとめておこうと思います。

FormerlySerializedAsAttributeについて

FormerlySerializedAsAttributeはフィールド名をリネームしたとき、前のフィールド名でシリアライズされていた場合でも読み込めるようにする属性です。

シリアライズされた値を失わないようにフィールド名のリネームをしたい場合、この属性を使用します。

Serialization.FormerlySerializedAsAttribute - Unity スクリプトリファレンス

例えばhogeというフィールド名からfugaにリネームしたとき、以下のように対応できます。

// hogeからfugaにリネームしても、値が引き継がれる
[FormerlySerializedAs("hoge")]
[SerializeField]
private int fuga;

より詳細

実際にフィールドがどのようにシリアライズされ保存されているのか調べればより分かりやすいです。

まずはhogeというフィールドがある場合、シーンファイル(中身はyaml等)などにはhoge: 100のように書き込まれます。

[SerializeField] private int hoge;
hoge: 100

これに対して[FormerlySerializedAs("hoge")]のように属性を付与すると、hoge: 100fugaの値として読み取ることができます。

またその状態で再度シリアライズが行われると、yamlにはリネーム後のキーが書き込まれます。

fuga: 100

つまり[FormerlySerializedAs]は指定した値でも読み込むことができるようになる属性です。書き込みに対しては対応されていないので注意してください。

プロパティでも利用できるか

本題ですが、プロパティでもFormerlySerializedAsAttributeを利用できます。

// 「<Hoge>k__BackingField: 100」のようにシリアライズされている
[field: FormerlySerializedAs("<Hoge>k__BackingField")]
[field: SerializeField] 
public float Fuga { get; set; }

引数の指定なんやねんと思うかと思いますが、バッキングフィールドというものでコンパイラが裏で生成してくれてるフィールドの名前です。(コンパイラ依存なので我々がどうにかできるものではありません)

<MyProperty>__BackingField

そしてUnityYamlはフィールド名をそのままyamlに書き込むので、以下のように記述されます。

<Hoge>k__BackingField: 200

[field: SerializeField]について

一応[field: SerializeField]でも[field: FormerlySerializedAs]を利用することができます。

ただ途中にも書きましたがバッキングフィールドはコンパイラー依存であり、UnityはMonoからCoreCLRへの移行を推進しています。そうそう変更は入らないとは思いますしUnityがある程度互換性を維持してくれる(それこそUnityYAMLを弄ったり)と信じてはいますが、[field: SerializedField]を利用しているとバージョンをあげたらアセット差分がめっちゃ出るとか、最悪読み取れないとかの可能性もゼロではないと思います。

個人的には利用しないを推奨したいです。