はじめに
今回は自作Attribute
の作り方とそれを利用した応用例のサンプルを紹介したいと思います。
作り方
System.Attributeを直接的・間接的に継承した派生クラスを作成することで自作Attribute
を作成できます。
またクラス名は〇〇Attribute
のように付けることが推奨されています。
public class AuthorAttribute : System.Attribute { }
コンストラクターとパブリックな読み取り/書き込みフィールドまたはプロパティ
public class AuthorAttribute : System.Attribute { private string name; public double version; public AuthorAttribute(string name) { this.name = name; version = 1.0; } }
コンストラクターのパラメーター・パブリックな読み取り/書き込みフィールドまたはプロパティについて、公式ドキュメントでは以下のように表記されています。
コンストラクターのパラメーターはカスタム属性の位置指定パラメーターです。 この例では、name が位置指定パラメーターになります。 パブリックな読み取り/書き込みフィールドまたはプロパティは名前付きパラメーターです。 この場合は、version が唯一の名前付きパラメーターです。
少し分かりにくいですが、コンストラクターのパラメーターは以下のように指定できます。
[Author("Name")]
対してpublic
なフィールド・プロパティは以下のように指定します。
[Author("Name", version = 2.0)]
System.AttributeUsageの利用
System.AttributeUsage
属性を自作Attribute
に対して使用することで、以下のような制限をつけることができます。
C# コンパイラによって解釈される属性: その他 | Microsoft Docs
[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct) ] public class AuthorAttribute : System.Attribute { private string name; public double version; public AuthorAttribute(string name) { this.name = name; version = 1.0; } }
また規定値は以下のようですね。
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
プロパティ名 | 意味 |
---|---|
ValidOn | この位置指定パラメーターは、指定された属性を配置できるプログラム要素を指定します。 |
AllowMultiple | 指定された属性を特定のプログラム要素に対して複数指定できるかどうかを指定します。 |
Inherited | 指定された属性を派生クラスとオーバーライドするメンバーによって継承できるかどうかを指定します。 |
リフレクションで属性の情報を取得
属性の情報を読み取る手段としてリフレクションを利用します。
docs.microsoft.com
public class CustomAttribute : Attribute { public readonly int value; public CustomAttribute(int value) { this.value = value; } } [CustomAttribute(2)] public class SampleClass { [CustomAttribute(5)] public string sampleField; [CustomAttribute(9)] public string SampleProperty { get; set; } [CustomAttribute(4)] public void SampleMethod() { } }
// クラスに付与されたCustomAttributeの情報を取り出す var customAttribute = typeof(SampleClass).GetCustomAttribute<CustomAttribute>(); Console.WriteLine(customAttribute.value); // 2 // メソッドに付与されたCustomAttributeの情報を取り出す customAttribute = typeof(SampleClass).GetMethod("SampleMethod").GetCustomAttribute<CustomAttribute>(); Console.WriteLine(customAttribute.value); // 4 // フィールドに付与されたCustomAttributeの情報を取り出す customAttribute = typeof(SampleClass).GetField("sampleField").GetCustomAttribute<CustomAttribute>(); Console.WriteLine(customAttribute.value); // 5 // プロパティに付与されたCustomAttributeの情報を取り出す customAttribute = typeof(SampleClass).GetProperty("SampleProperty").GetCustomAttribute<CustomAttribute>(); Console.WriteLine(customAttribute.value); // 9
UnityのPropertyAttribute
UnityにはPropertyAttribute
というSystem.Attribute
を継承したクラスが用意されており、PropertyDrawer
と組み合わせることでインスペクターでの表示を変更することができます。
カスタムプロパティー属性を派生させるベースクラス。これを使用してスクリプト変数のカスタム属性を作成します。
カスタム属性は PropertyDrawer クラスと連結して、その属性があるスクリプト変数がインスペクター上でどう表示されるか制御します。
UnityEngine.PropertyAttribute - Unity スクリプトリファレンス
Unity内部の実装はシンプルで、以下のように実装されています。
// Base class to derive custom property attributes from. Use this to create custom attributes for script variables. [System.AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)] [UnityEngine.Scripting.UsedByNativeCode] public abstract class PropertyAttribute : Attribute { public int order { get; set; } }
UnityCsReference/PropertyAttribute.cs at master · Unity-Technologies/UnityCsReference · GitHub
Unityで実装されているPropertyAttribute
UnityではPropertyAttribute
を継承している属性が複数あります。
UnityCsReference/PropertyAttribute.cs at master · Unity-Technologies/UnityCsReference · GitHub
// Attribute used to make a float or int variable in a script be restricted to a specific range. [System.AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)] public sealed class RangeAttribute : PropertyAttribute { public readonly float min; public readonly float max; // Attribute used to make a float or int variable in a script be restricted to a specific range. public RangeAttribute(float min, float max) { this.min = min; this.max = max; } }
基本全部public readonly
なフィールド&コンストラクタで設定というパターンなようです。
自作PropertyAttribute
public class DisableAttribute : PropertyAttribute { }
PropertyDrawer
を継承したクラスを利用することで、PropertyAttribute
にアクセスし、インスペクターの表示を変更することができます。
UnityEditor.PropertyDrawer - Unity スクリプトリファレンス
[CustomPropertyDrawer(typeof(DisableAttribute))] public class DisableDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EditorGUI.BeginDisabledGroup(true); EditorGUI.PropertyField(position, property, label); EditorGUI.EndDisabledGroup(); } }
実際に利用してみると以下のようになります。
public class Test : MonoBehaviour { [Disable] public string sample; }
またAttribute
内の変数を利用したい場合は、PropertyDrawer.attribute
を利用します。
DisableAttribute range = (DisableAttribute)attribute;