Enumの各要素にAttributeをつけることで要素ごとに情報を付加します。
やりたいこと
たとえば、Enumの要素ごとにアトリビュートで日本語名をつけて、
public enum AndroidCode { [Name("マシュマロ")] Marshmallow, [Name("ヌガー")] Nougat, [Name("オレオ")] Oreo, [Name("パイ")] Pie }
Inspectorで表示されるようにしたい。
こんな感じのものを今回のゴールとします。
ソースコード
Enumの要素用のAttribute、Enum自体につけるPropertyAttribute、PropertyAttributeのDrawerをそれぞれ作ります。
using System.Collections.Generic; using UnityEngine; using System.Linq; #if UNITY_EDITOR using UnityEditor; #endif // Enumの要素に付けるAttribute // PropertyAttributeではなくSystem.Attributeを継承する [System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Enum, AllowMultiple = false)] public class EnumElementAttribute : System.Attribute { public string DisplayName { get; private set; } public EnumElementAttribute(string displayName) { DisplayName = displayName; } } // Enum自体に付けるAttribute // これはPropertyDrawerで使うのでPropertyAttributeを継承する [System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Enum, AllowMultiple = false)] public class EnumElementUsageAttribute : PropertyAttribute { public System.Type Type { get; private set; } public EnumElementUsageAttribute(System.Type selfType) { Type = selfType; } } #if UNITY_EDITOR [CustomPropertyDrawer(typeof(EnumElementUsageAttribute))] public class EnumAttributeDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { var attr = attribute as EnumElementUsageAttribute; // FieldInfoから各要素のAttributeを取得し名前を得る var names = new List<string>(); foreach (var fi in attr.Type.GetFields()) { if (fi.IsSpecialName) { // SpecialNameは飛ばす continue; } var elementAttribute = fi.GetCustomAttributes(typeof(EnumElementAttribute), false).FirstOrDefault() as EnumElementAttribute; names.Add(elementAttribute == null ? fi.Name : elementAttribute.DisplayName); } // 各要素の値はEnum.GetValues()で取得する var values = System.Enum.GetValues(attr.Type).Cast<int>(); // 描画 property.intValue = EditorGUI.IntPopup(position, property.displayName, property.intValue, names.ToArray(), values.ToArray()); } } #endif
Enumの要素につけるAttributeはPropertyAttributeではなくSystem.Attributeを継承しています。
Inspectorに表示するフィールドでない場合はSystem.Attributeで十分です。
結果
前節のAttributeを次のようにして使います。
using UnityEngine; public class EnumElementAttributeExample : MonoBehaviour { public enum AndroidCode { [EnumElement("マシュマロ")] Marshmallow, [EnumElement("ヌガー")] Nougat, [EnumElement("オレオ")] Oreo, [EnumElement("パイ")] Pie } [SerializeField, EnumElementUsage(typeof(AndroidCode))] private AndroidCode _code; }
Inspectorには次のように表示されます。