Enumを簡単にStringとしてシリアライズできるパッケージ作りました
github.comkyubuns/StringSerializableEnum
なにこれ?
こんなコードを書いてEnumをシリアライズすると、
.unityや.prefabを見ればわかるように、内部的には0, 1, 2というintの値として保存されます。
TestMonoBehaviour.cs
public class TestMonoBehaviour : MonoBehaviour
{
[SerializeField] private TestEnum testEnum;
}
public enum TestEnum
{
Zero,
One,
Two,
}つまり、Enumの途中に値を追加/削除すると意図しない指定の変更が起きてしまいます。
TestEnum.cs
public enum TestEnum
{
Zero,
Half, // <- おっと、0.5も必要だった
One,
Two,
}↓ "One" を指定していたはずなのに!
正攻法としては、ちゃんと手動で数値を振るということになるのですが、
Unityのシリアライザーのためにこの作業が必要になるのが気に食わない。(個人の主観です。)
TestEnum.cs
public enum TestEnum
{
Zero = 0,
Half = 3, // ← 後から追加した
One = 1,
Two = 2,
}ということで、Stringとしてシリアライズしてくれるパッケージを作りました。
使い方
- UnityPackageManagerで
https://github.com/kyubuns/StringSerializableEnum.git?path=Unity/Assets/StringSerializableEnumをインストール。 - StringとしてシリアライズしたいEnumに
[StringSerializable]をつける。
TestEnum.cs
[StringSerializable]
public enum TestEnum
{
One,
Two,
Three,
}StringSerializable{Enum名}という型が自動生成されるので、それをシリアライズしてお使いください。
TestMonoBehaviour.cs
public class TestMonoBehaviour : MonoBehaviour
{
[SerializeField] private StringSerializableTestEnum testEnum;
public void Start()
{
Debug.Log($"Value is {testEnum.Value}");
}
}見た目は変わらず。でもズレない!
差分も見やすくて嬉しい。
Q&A
じゃあ名前を変更すると?
Inspectorではエラー表示になり、このまま実行するとランタイムで例外を吐きます。
Enumの名前が変わるのと数値が変わるの、同じぐらいのリスクじゃない?
ぶっちゃけ同じだと思ってます。ただの思想の問題。
やろうと思えば静的にチェックもできるので少しだけ嬉しいかも?
StringとEnumの変換遅くない?
以下のようにswitchに展開してるので Enum.TryParse よりは十分に早いです。
(が、高速化は専門じゃないのでもっと良い方法あれば教えてください。)
TestEnum.cs
public TestEnum Value
{
get
{
if (_cached == null)
{
_cached = stringValue switch
{
"Zero" => TestEnum.Zero,
"One" => TestEnum.One,
"Two" => TestEnum.Two,
_ => throw new ArgumentOutOfRangeException($"\"{stringValue}\" is not a valid value for TestEnum")
};
}
return _cached.Value;
}
}