SerializeReference属性についてのまとめ
from UnityのUndo/Redoについてのまとめ
【Unity】SerializeReferenceをちゃんと理解する
従来のSerializedField属性の問題点
非UnityEngine.Objectなクラスのインスタンスは値としてシリアライズされる
抽象クラスやインタフェースには非対応
ただし、Unity2020.1からはGenericな型をSerializeFieldでシリアライズできるようになっている
SerializeReferenceは非UnityEngine.Objectのための機能
まず前提として、SerializeReferenceはUnityEngine.Objectを継承した型ではない型の参照をシリアライズするためのものです。
前述の通り、SerializeFieldはUnityEngine.Objectの派生型の参照をシリアライズできるのでそっちを使えばOKです。
UnityEngine.Objectの派生クラスにSerializedReference属性を適用するとエラーが出る
抽象型やインタフェース型のフィールドをシリアライズできる
参照を二つのMonoBehaviour間で共有することはできない
これは公式のドキュメントで仕様を確認しておきたい
nullを表現できる
SerializeField属性を適用したフィールドをnullにすることはできない
スクリプトのシリアル化
シリアライズ時にnullになっているフィールドは、インスタンスが新たに生成されてからシリアライズされる
SerializeRerference属性を適用したフィールドがnullになっていた場合、逆シリアライズ時にもnullになる
Genericを使ったクラスのインスタンスには使えない
SerializeReferenceの使いどころ
グラフ構造やツリー構造をシリアライズする
インラインでシリアライズされる場合に問題が発生する例としてよく挙げられていたので、例としては鉄板
エディタの入力インタフェースを手間なく切り替えられる
つまりポリモーフィズム
SerializedFieldでは、シリアライズ時にインスタンスの型ではなくフィールドの型が使用されていたため、派生クラスのフィールドをシリアライズできなかった
例示されているコードでは、Skillクラスの派生としてAtackSkillとBuffSkillがあり、SerializeReference属性を適用したSkillフィールドに格納されている
Skillフィールドに格納されているインスタンスの型に応じてインスペクタの表示が切り替わっている
振る舞いをエディタから変更できる
こちらもポリモーフィズム
MonoBehaviourのStart()の挙動を、インスペクタから_speakerフィールドの値を差し替えることで変更している
参照が保持できるようになったことでポリモーフィズムを活用できるのは非常に大きなメリットなので、積極的に使っていきたい
https://twitter.com/am1tanaka/status/1546799253863174146
リストや配列にSerializeReference 属性つけて定義すると設定するインスタンスの情報を直にシーンファイルに埋め込まずに参照を作ってくれるのでシーンファイルが変更に強くなるとな。とても良さげなのでSerializeReference属性を忘れ去らないよう頑張らねば
「シーンファイルが変更に強くなる」というのは何を意味している?
Unity 2021 LTS における SerializeReference の改善点
最近では、Unity 2021 LTS でマネージ参照に Stable ID が導入され、欠落している型のきめ細かい処理と API アクセスの向上が実現されました。
逆に、それ以前のバージョンでSerializeReferenceを使用する場合は注意が必要
Stable ID
Unity2020以前の仕様では、SerializeReference属性が適用されたフィールドの参照先のオブジェクトについて、シリアライズの際にIDが割り振られていた
そのため、オブジェクトの内容に変更がない場合でも、例えば要素の入れ替えの際などにIDの振り直しが発生し、シーンファイル等の差分が大きくなってしまっていた
これにより、マージ時のコンフリクト修正が大変になったりする
また、参照先のIDが 0, 1, 2, 3... のような形で割り振られるため、同時に複数ユーザが変更を行った場合にIDの衝突が起こる可能性が高かった
Unity2021以降の仕様では、参照先のオブジェクトに対して固有のIDが割り振られ、シリアライズのたびに変化することがないので、シリアライズされたファイルの差分が少なく抑えられる
IDは時刻とシステム情報のハッシュ値に基づいて生成されるため、衝突にも強くなった
また、prefabの参照にもStable IDが使用されるようになったため、参照元オブジェクトの変更によるprefabの破損が発生しにくくなった
欠落している型の処理
SerializeReference属性が適用されたフィールドが逆シリアライズされる際、格納されたオブジェクトのクラス定義が見つからない可能性がある
シリアライズされた際はスクリプトにクラス定義が含まれていたが、逆シリアライズの際にクラス定義が削除されていた場合などに発生
Unity2020以前の仕様では、参照先のクラス定義が欠落している場合、参照元のオブジェクトでエラーが発生し、すべての参照先がインスペクタに表示されなくなる
Unity2021以降の仕様では、クラス定義が欠落している参照先が存在した場合、その参照先だけをnullにする
また、エラーメッセージもUnity2020以前より分かりやすいものになっている
API サポートの改善
Unity2021以降では新しくSerializtionUnilityクラスが追加され、シリアライズに関する処理がそちらのクラスに実装されうようになった
互換性には配慮されているため、あまり気にしなくてもいい
#Unity