カスタム属性の記述
更新 : 2007 年 11 月
独自のカスタム属性をデザインするために、いくつもの新しい概念をマスターする必要はありません。オブジェクト指向プログラミングの経験があり、クラスのデザイン方法を知っている場合は、必要な知識のほとんどを既に持っています。カスタム属性は、基本的には、System.Attribute から直接または間接的に派生する普通のクラスです。普通のクラスと同様に、カスタム属性にはデータを格納したり取得したりするメソッドがあります。
カスタム属性クラスを正しくデザインするための主要な手順は次のとおりです。
AttributeUsageAttribute の適用
属性クラスの宣言
コンストラクタの宣言
プロパティの宣言
ここでは、上の各手順について説明し、最後にカスタム属性の例を示します。
AttributeUsageAttribute の適用
カスタム属性の宣言は、AttributeUsageAttribute から始まります。AttributeUsageAttribute は、属性クラスのいくつかの主要な特性を定義します。たとえば、属性をほかのクラスで継承できるかどうかを指定したり、属性を適用できる要素を指定したりできます。次のコードでは、AttributeUsageAttribute をどのように使用するかについて示します。
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
<AttributeUsage(AttributeTargets.All, Inherited := False, AllowMultiple := true)>
System.AttributeUsageAttribute には、カスタム属性の作成で重要な 3 つのメンバ、AttributeTargets、Inherited、および AllowMultiple があります。
AttributeTargets のメンバ
前の例で指定されている AttributeTargets.All は、この属性をすべてのプログラム要素に適用できることを示します。これ以外に、属性を 1 つの特定のクラスにだけ適用できることを示す AttributeTargets.Class や、属性を 1 つの特定のメソッドにだけ適用できることを示す AttributeTargets.Method も指定できます。この方法でカスタム属性を使用して、すべてのプログラム要素をマーキングできます。
また、AttributeTargets の複数のインスタンスを渡すこともできます。カスタム属性を任意のクラスやメソッドに適用できるように指定するコード片を次に示します。
[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)]
<AttributeUsage (AttributeTargets.Class Or AttributeTargets.Method)>
Inherited プロパティ
Inherited プロパティは、属性が適用されるクラスから継承されるクラスが、その属性を継承できるかどうかを指定します。このプロパティには、true (既定値) または false のいずれかのフラグが指定できます。たとえば次のコード例では、MyAttribute の Inherited の値は既定値の true ですが、YourAttribute の Inherited の値は false です。
//This defaults to Inherited = true.
public class MyAttribute :Attribute
{
}
[AttributeUsage( Inherited = false)]
public class YourAttribute : Attribute
{
}
<AttributeUsage( AttributeTargets.All, Inherited := True)> Public Class _
MyAttribute
Inherits Attribute
End Class
<AttributeUsage( AttributeTargets.All, Inherited := False)> Public Class _
YourAttribute
Inherits Attribute
End Class
2 つの属性は、基本クラス MyClass 内のメソッドに次のように適用されます。
public class MyClass
{
[MyAttribute]
[YourAttribute]
public virtual void MyMethod()
{
//...
}
}
' In Microsoft Visual Basic, you apply multiple attributes
' by separating them with commas.
Public Class [MyClass]
<MyAttribute, YourAttribute> Public Overridable Sub MyMethod()
'...
End Sub
End Class
最後に、基本クラス MyClass から YourClass クラスが継承されます。メソッド MyMethod は、YourAttribute ではなく MyAttribute を示します。
public class YourClass: MyClass
{
//MyMethod will have MyAttribute but not YourAttribute.
public override void MyMethod()
{
//...
}
}
Public Class YourClass
Inherits [MyClass]
'MyMethod will have MyAttribute but not YourAttribute.
Public overrides Sub MyMethod()
'...
End Sub
End Class
AllowMultiple プロパティ
AllowMultiple プロパティは、1 つの要素に対して属性の複数のインスタンスが存在できるかどうかを示します。このプロパティを true に設定すると、複数のインスタンスが存在でき、false (既定値) に設定すると、1 つのインスタンスだけが存在できます。
MyAttribute の AllowMultiple の値が既定値の false、YourAttribute の値が true のコード例を次に示します。
//This defaults to AllowMultiple = false.
public class MyAttribute :Attribute
{
}
[AttributeUsage(AllowMultiple = true)]
public class YourAttribute : Attribute
{
}
'This defaults to AllowMultiple = false.
<AttributeUsage(AttributeTargets.Method)> Public Class _
MyAttribute
Inherits Attribute
End Class
<AttributeUsage(AttributeTargets.Method, AllowMultiple := True)> Public Class _
YourAttribute
Inherits Attribute
End Class
これらの属性の複数のインスタンスが適用されたとき、MyAttribute ではコンパイル エラーが生成されます。正しく使われている YourAttribute と、不適切に使われている MyAttribute の例を次に示します。
public class MyClass
{
//This produces an error.
//Duplicates are not allowed.
[MyAttribute]
[MyAttribute]
public void MyMethod() {
//...
}
//This is valid.
[YourAttribute]
[YourAttribute]
public void YourMethod(){
//...
}
}
' In Microsoft Visual Basic you apply multiple attributes
' by separating them with commas.
Public Class [MyClass]
'This produces an error.
'Duplicates are not allowed.
<MyAttribute, MyAttribute> Public Overridable Sub MyMethod()
'...
End Sub
'This is valid.
<YourAttribute, YourAttribute> Public Sub YourMethod()
'...
End Sub
End Class
AllowMultiple プロパティと Inherited プロパティの両方が true に設定されている場合は、あるクラスから派生したクラスは属性を継承でき、同じ子クラスに同じ属性が適用される別のインスタンスを持つことができます。AllowMultiple が false に設定されている場合は、親クラスでの属性の値が、子クラスにおける同じ属性の新しいインスタンスによって上書きされます。
属性クラスの宣言
AttributeUsageAttribute を適用した後で、属性の仕様を定義できます。属性クラスの宣言は、次のコードに示すように、普通のクラスの宣言に似ています。
public class MyAttribute : System.Attribute
{
// . . .
}
' This attribute is only usable with methods
<AttributeUsage(AttributeTargets.Method)> Public Class MyAttribute
Inherits System.Attribute
' . . .
End Class
この属性定義では、次の点が示されています。
属性クラスは、パブリック クラスとして宣言する必要があります。
規則では、属性クラスの名前の最後は Attribute にします。この規則は必須ではありませんが、クラス名をわかりやすくするために、この規則に従うことをお勧めします。属性を適用するとき、「Attribute」は省略できます。
すべての属性クラスは、System.Attribute から直接または間接的に継承する必要があります。
Microsoft Visual Basic では、すべてのカスタム属性クラスが AttributeUsageAttribute 属性を持つ必要があります。
コンストラクタの宣言
属性をコンストラクタで初期化する方法は、普通のクラスの場合と同じです。次のコードは、一般的な属性のコンストラクタを示します。このパブリック コンストラクタは 1 つのパラメータをとり、メンバ変数と等しい値に設定します。
public MyAttribute(bool myvalue)
{
this.myvalue = myvalue;
}
Public Sub New(newvalue As Boolean)
Me.myvalue = newvalue
End Sub
コンストラクタをオーバーロードすることによって、ほかの値の組み合わせを使用できます。カスタム属性クラスのプロパティも定義すると、属性を初期化するときに、名前付きパラメータと位置指定パラメータの組み合わせを使用できます。通常は、すべての必須パラメータを位置指定パラメータとして定義し、すべてのオプション パラメータを名前付きパラメータとして定義します。この場合は、必須パラメータがないと属性を初期化できません。ほかのすべてのパラメータはオプションです。Visual Basic では、属性クラスのコンストラクタには ParamArray 引数を使用できません。
次のコードでは、前のコンストラクタを使用する属性を必須パラメータとオプション パラメータを使用して適用する方法を示します。このコード例では、属性が、必須パラメータとして 1 つのブール値を、オプション パラメータとして 1 つの文字列プロパティを持つことを想定しています。
//One required (positional) and one optional (named) parameter are applied.
[MyAttribute(false, OptionalParameter = "optional data")]
//One required (positional) parameter is applied.
[MyAttribute(false)]
'One required (positional) and one optional (named) parameter are applied.
<MyAttribute(False, OptionalParameter := "optional data")>
' ...
'One required (positional) parameter is applied.
<MyAttribute(False)>
プロパティの宣言
名前付きパラメータを定義する場合、または属性によって格納される値を簡単に返す手段を用意する場合は、プロパティを宣言します。属性のプロパティは、返されるデータ型の記述を持つパブリック エンティティとして宣言する必要があります。プロパティの値を保持する変数を定義してから、それに get メソッドと set メソッドを関連付けます。次のコードは、属性に簡単なプロパティを実装する方法を示します。
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 class DeveloperAttribute : System.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 System.Attribute
'Private fields.
Private m_name As String
Private m_level As String
Private m_reviewed As Boolean
'This constructor defines two required parameters: name and level.
Public Sub New(name As String, level As String)
Me.m_name = name
Me.m_level = level
Me.m_reviewed = False
End Sub
'Define Name property.
'This is a read-only attribute.
Public Overridable ReadOnly Property Name() As String
Get
Return m_name
End Get
End Property
'Define Level property.
'This is a read-only attribute.
Public Overridable ReadOnly Property Level() As String
Get
Return m_level
End Get
End Property
'Define Reviewed property.
'This is a read/write attribute.
Public Overridable Property Reviewed() As Boolean
Get
Return m_reviewed
End Get
Set
m_reviewed = value
End Set
End Property
End Class
この属性は、フルネーム DeveloperAttribute または省略名 Developer を使用して、次のいずれかの方法で適用できます。
[Developer("Joan Smith", "1")]
[Developer("Joan Smith", "1", Reviewed = true)]
<Developer("Joan Smith", "1")>
<Developer("Joan Smith", "1", Reviewed := True)>
最初の例は、名前付き必須パラメータだけを使用して適用される属性です。2 番目の例は、必須パラメータとオプション パラメータの両方を使用して適用される属性です。