カスタム属性を記述する
カスタム属性を設計するために、多くの新しい概念を学習する必要はありません。 オブジェクト指向プログラミングに精通してクラスを設計する方法を理解しているなら、必要な知識をほぼすべて持っています。 カスタム属性は、System.Attribute クラスから直接または間接的に派生した従来のクラスです。 従来のクラスと同じように、カスタム属性には、データを格納したり取得したりするメソッドが含まれます。
カスタム属性クラスを適切にデザインするための主要な手順は次のとおりです。
このセクションでは、これらの各手順について説明し、最後に カスタム属性の例について説明します。
AttributeUsageAttribute を適用する
カスタム属性宣言は System.AttributeUsageAttribute 属性で始まり、属性クラスの主な特性のいくつかを定義します。 たとえば、属性が他のクラスによって継承されるかどうかを指定したり、属性を適用する要素を指定したりすることができます。 次のコード フラグメントは、AttributeUsageAttribute の使い方を示しています。
[AttributeUsage(AttributeTargets::All, Inherited = false, AllowMultiple = true)]
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
<AttributeUsage(AttributeTargets.All, Inherited:=False, AllowMultiple:=True)>
Public Class SomeClass
Inherits Attribute
'...
End Class
AttributeUsageAttribute には、カスタム属性を作成するために重要な 3 つのメンバー(AttributeTargets、Inherited、AllowMultiple) があります。
AttributeTargets メンバー
前の例では、AttributeTargets.All を指定し、この属性をすべてのプログラム要素に適用できることが示されています。 代わりに、属性をクラスにのみ適用できることを示す AttributeTargets.Class を指定するか、属性をメソッドにのみ適用できることを示す AttributeTargets.Method を指定できます。 この方法で、カスタム属性を使って、説明としてすべてのプログラム要素をマークすることができます。
また、複数の AttributeTargets の値を渡すこともできます。 次のコード フラグメントは、すべてのクラスやメソッドに適用できるカスタム属性を指定します。
[AttributeUsage(AttributeTargets::Class | AttributeTargets::Method)]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
<AttributeUsage(AttributeTargets.Class Or AttributeTargets.Method)>
Public Class SomeOtherClass
Inherits Attribute
'...
End Class
Inherited プロパティ
AttributeUsageAttribute.Inherited プロパティは、属性が、その属性が適用されたクラスから派生したクラスによって継承可能かどうかを示します。 このプロパティは、true
(既定) か false
フラグのいずれかを使います。 次の例では、MyAttribute
には true
の既定の Inherited 値が指定されていますが、YourAttribute
には false
の Inherited 値が指定されています。
// This defaults to Inherited = true.
public ref class MyAttribute : Attribute
{
//...
};
[AttributeUsage(AttributeTargets::Method, Inherited = false)]
public ref class YourAttribute : Attribute
{
//...
};
// This defaults to Inherited = true.
public class MyAttribute : Attribute
{
//...
}
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class YourAttribute : Attribute
{
//...
}
' This defaults to Inherited = true.
Public Class MyAttribute
Inherits Attribute
'...
End Class
<AttributeUsage(AttributeTargets.Method, Inherited:=False)>
Public Class YourAttribute
Inherits Attribute
'...
End Class
その後、2 つの属性が基底クラス MyClass
に適用されます。
public ref class MyClass
{
public:
[MyAttribute]
[YourAttribute]
virtual void MyMethod()
{
//...
}
};
public class MyClass
{
[MyAttribute]
[YourAttribute]
public virtual void MyMethod()
{
//...
}
}
Public Class MeClass
<MyAttribute>
<YourAttribute>
Public Overridable Sub MyMethod()
'...
End Sub
End Class
最後に、クラス YourClass
が基底クラス MyClass
から継承されます。 メソッド MyMethod
により MyAttribute
は表示されますが、YourAttribute
は表示されません。
public ref class YourClass : MyClass
{
public:
// MyMethod will have MyAttribute but not YourAttribute.
virtual void MyMethod() override
{
//...
}
};
public class YourClass : MyClass
{
// MyMethod will have MyAttribute but not YourAttribute.
public override void MyMethod()
{
//...
}
}
Public Class YourClass
Inherits MeClass
' MyMethod will have MyAttribute but not YourAttribute.
Public Overrides Sub MyMethod()
'...
End Sub
End Class
AllowMultiple プロパティ
AttributeUsageAttribute.AllowMultiple プロパティは、1 つの要素に、属性の複数のインスタンスが存在できるかどうかを示します。 true
に設定すると、複数のインスタンスが許可されます。 false
(既定値) に設定すると、1 つのインスタンスのみが許可されます。
次の例では、MyAttribute
には false
の既定の AllowMultiple 値が指定されていますが、YourAttribute
には true
値が指定されています。
//This defaults to AllowMultiple = false.
public ref class MyAttribute : Attribute
{
};
[AttributeUsage(AttributeTargets::Method, AllowMultiple = true)]
public ref class YourAttribute : Attribute
{
};
//This defaults to AllowMultiple = false.
public class MyAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class YourAttribute : Attribute
{
}
' This defaults to AllowMultiple = false.
Public Class MyAttribute
Inherits Attribute
End Class
<AttributeUsage(AttributeTargets.Method, AllowMultiple:=true)>
Public Class YourAttribute
Inherits Attribute
End Class
これらの属性の複数のインスタンスが適用されると、 MyAttribute
ではコンパイラ エラーが発生します。 次のコード例は、YourAttribute
の正しい使い方と MyAttribute
の正しくない使い方を示しています。
public ref class MyClass
{
public:
// This produces an error.
// Duplicates are not allowed.
[MyAttribute]
[MyAttribute]
void MyMethod()
{
//...
}
// This is valid.
[YourAttribute]
[YourAttribute]
void YourMethod()
{
//...
}
};
public class MyClass
{
// This produces an error.
// Duplicates are not allowed.
[MyAttribute]
[MyAttribute]
public void MyMethod()
{
//...
}
// This is valid.
[YourAttribute]
[YourAttribute]
public void YourMethod()
{
//...
}
}
Public Class MyClass
' This produces an error.
' Duplicates are not allowed.
<MyAttribute>
<MyAttribute>
Public Sub MyMethod()
'...
End Sub
' This is valid.
<YourAttribute>
<YourAttribute>
Public Sub YourMethod()
'...
End Sub
End Class
AllowMultiple プロパティと Inherited プロパティの両方が true
に設定されている場合、別のクラスから継承されるクラスは属性を継承し、同じ子クラスに適用される同じ属性の別のインスタンスを持つことができます。 AllowMultiple が false
に設定されている場合、親クラスのすべての属性の値は、子クラスの同じ属性の新しいインスタンスによって上書きされます。
属性クラスを宣言する
AttributeUsageAttribute を適用したら、属性の詳細の定義を開始します。 属性クラスの宣言は、次のコードに示すように、従来のクラスの宣言に似ています。
[AttributeUsage(AttributeTargets::Method)]
public ref class MyAttribute : Attribute
{
// . . .
};
[AttributeUsage(AttributeTargets.Method)]
public class MyAttribute : Attribute
{
// . . .
}
<AttributeUsage(AttributeTargets.Method)>
Public Class MyAttribute
Inherits Attribute
' . . .
End Class
この属性定義は、次の点を示します。
属性クラスはパブリック クラスとして宣言する必要があります。
規則により、属性クラスの名前の終わりに Attributeという単語を付けます。 必須ではありませんが、読みやすさの向上のために、この規定をお勧めします。 属性を適用すると、Attribute という単語を含める必要はなくなります。
すべての属性クラスは、System.Attribute クラスから直接的に継承するか間接的に継承する必要があります。
Microsoft Visual Basic では、すべてのカスタム属性クラスに System.AttributeUsageAttribute 属性が必要です。
コンストラクターを宣言する
従来のクラスと同じように、属性はコンストラクターで初期化されます。 次のコード フラグメントは、一般的な属性のコンストラクターを示しています。 このパブリック コンストラクターは、パラメーターを使って、メンバー変数と同じ値を設定します。
MyAttribute(bool myvalue)
{
this->myvalue = myvalue;
}
public MyAttribute(bool myvalue)
{
this.myvalue = myvalue;
}
Public Sub New(myvalue As Boolean)
Me.myvalue = myvalue
End Sub
さまざまな値の組み合わせに対応するように、コンストラクターをオーバーロードできます。 カスタム属性クラスの プロパティ も定義する場合、属性を初期化する際に、名前付きパラメーターと位置指定パラメーターの組み合わせを使うことができます。 通常、必須パラメーターすべてを位置指定パラメーター、省略可能なパラメーターすべてを名前付きパラメーターとして定義します。 この場合、属性は必須パラメーターがないと初期化できません。 その他のパラメーターはすべて省略可能です。
Note
Visual Basic では、属性クラスのコンストラクターで ParamArray
引数を使うべきではないことに注意してください。
次のコード例は、省略可能なパラメーターと必須パラメーターを使って、前のコンストラクターを使う属性を適用できることを示しています。 ここでは、属性には、必須のブール値 1 つと省略可能な文字列のプロパティ 1 つが含まれていることを前提としています。
// One required (positional) and one optional (named) parameter are applied.
[MyAttribute(false, OptionalParameter = "optional data")]
public ref class SomeClass
{
//...
};
// One required (positional) parameter is applied.
[MyAttribute(false)]
public ref class SomeOtherClass
{
//...
};
// One required (positional) and one optional (named) parameter are applied.
[MyAttribute(false, OptionalParameter = "optional data")]
public class SomeClass
{
//...
}
// One required (positional) parameter is applied.
[MyAttribute(false)]
public class SomeOtherClass
{
//...
}
' One required (positional) and one optional (named) parameter are applied.
<MyAttribute(false, OptionalParameter:="optional data")>
Public Class SomeClass
'...
End Class
' One required (positional) parameter is applied.
<MyAttribute(false)>
Public Class SomeOtherClass
'...
End Class
プロパティを宣言する
名前付きパラメーターを定義するか、属性によって格納される値を簡単に返すことができるようにする場合、 プロパティを宣言します。 属性プロパティは、返されるデータ型の記述を添えて、パブリック エンティティとして宣言する必要があります。 プロパティの値を保持する変数を定義して、その変数を get
メソッドと set
メソッドに関連付けます。 次のコード例は、属性にプロパティを実装する方法を示しています。
property bool MyProperty
{
bool get() {return this->myvalue;}
void set(bool value) {this->myvalue = value;}
}
public bool MyProperty
{
get {return this.myvalue;}
set {this.myvalue = value;}
}
Public Property MyProperty As Boolean
Get
Return Me.myvalue
End Get
Set
Me.myvalue = Value
End Set
End Property
カスタム属性の例
このセクションには、前の情報が含まれており、コードのセクションの作成者に関する情報を文書化する属性を設計する方法を示しています。 この例の属性は、プログラマの名前とレベル、またコードを確認したかどうかを格納します。 保存する実際の値を格納するため、3 つのプライベート変数を使います。 各変数は、値を取得して設定するパブリック プロパティで表されます。 最後に、コンストラクターを 2 つの必須パラメーターを使って定義します。
[AttributeUsage(AttributeTargets::All)]
public ref class DeveloperAttribute : Attribute
{
// Private fields.
private:
String^ name;
String^ level;
bool reviewed;
public:
// This constructor defines two required parameters: name and level.
DeveloperAttribute(String^ name, String^ level)
{
this->name = name;
this->level = level;
this->reviewed = false;
}
// Define Name property.
// This is a read-only attribute.
virtual property String^ Name
{
String^ get() {return name;}
}
// Define Level property.
// This is a read-only attribute.
virtual property String^ Level
{
String^ get() {return level;}
}
// Define Reviewed property.
// This is a read/write attribute.
virtual property bool Reviewed
{
bool get() {return reviewed;}
void set(bool value) {reviewed = value;}
}
};
[AttributeUsage(AttributeTargets.All)]
public class DeveloperAttribute : Attribute
{
// Private fields.
private string name;
private string level;
private bool reviewed;
// This constructor defines two required parameters: name and level.
public DeveloperAttribute(string name, string level)
{
this.name = name;
this.level = level;
this.reviewed = false;
}
// Define Name property.
// This is a read-only attribute.
public virtual string Name
{
get {return name;}
}
// Define Level property.
// This is a read-only attribute.
public virtual string Level
{
get {return level;}
}
// Define Reviewed property.
// This is a read/write attribute.
public virtual bool Reviewed
{
get {return reviewed;}
set {reviewed = value;}
}
}
<AttributeUsage(AttributeTargets.All)>
Public Class DeveloperAttribute
Inherits Attribute
' Private fields.
Private myname As String
Private mylevel As String
Private myreviewed As Boolean
' This constructor defines two required parameters: name and level.
Public Sub New(name As String, level As String)
Me.myname = name
Me.mylevel = level
Me.myreviewed = False
End Sub
' Define Name property.
' This is a read-only attribute.
Public Overridable ReadOnly Property Name() As String
Get
Return myname
End Get
End Property
' Define Level property.
' This is a read-only attribute.
Public Overridable ReadOnly Property Level() As String
Get
Return mylevel
End Get
End Property
' Define Reviewed property.
' This is a read/write attribute.
Public Overridable Property Reviewed() As Boolean
Get
Return myreviewed
End Get
Set
myreviewed = value
End Set
End Property
End Class
完全名 DeveloperAttribute
や省略名 Developer
を使って、次のいずれかの方法でこの属性を適用できます。
[Developer("Joan Smith", "1")]
-or-
[Developer("Joan Smith", "1", Reviewed = true)]
[Developer("Joan Smith", "1")]
-or-
[Developer("Joan Smith", "1", Reviewed = true)]
<Developer("Joan Smith", "1")>
-or-
<Developer("Joan Smith", "1", Reviewed := true)>
最初の例は、必須の名前付きパラメーターのみを使って適用された属性を示しています。 2 番目の例は、必須パラメーターと省略可能なパラメーターの両方を使って適用された属性を示しています。
関連項目
.NET