この記事の英語版を表示するには、[英語] のチェック ボックスをオンにしてください。また、テキストにマウス ポインターを合わせると、ポップアップ ウィンドウに英語のテキストを表示することもできます。
翻訳
英語
このドキュメントはアーカイブされており、メンテナンスされていません。

カスタム属性の記述

独自のカスタム属性をデザインするために、いくつもの新しい概念をマスターする必要はありません。 オブジェクト指向プログラミングの経験があり、クラスのデザイン方法を知っている場合は、必要な知識のほとんどを既に持っています。 カスタム属性は、基本的には、System.Attribute から直接または間接的に派生する普通のクラスです。 普通のクラスと同様に、カスタム属性にはデータを格納したり取得したりするメソッドがあります。

カスタム属性クラスを正しくデザインするための主要な手順は次のとおりです。

ここでは、上の各手順について説明し、最後にカスタム属性の例を示します。

カスタム属性の宣言は、AttributeUsageAttribute から始まります。AttributeUsageAttribute は、属性クラスのいくつかの主要な特性を定義します。 たとえば、属性をほかのクラスで継承できるかどうかを指定したり、属性を適用できる要素を指定したりできます。 次のコードでは、AttributeUsageAttribute をどのように使用するかについて示します。


[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]


System.AttributeUsageAttribute には、カスタム属性の作成で重要な 3 つのメンバー、AttributeTargetsInherited、および AllowMultiple があります。

AttributeTargets のメンバー

前の例で指定されている AttributeTargets.All は、この属性をすべてのプログラム要素に適用できることを示します。 これ以外に、属性を 1 つの特定のクラスにだけ適用できることを示す AttributeTargets.Class や、属性を 1 つの特定のメソッドにだけ適用できることを示す AttributeTargets.Method も指定できます。 この方法でカスタム属性を使用して、すべてのプログラム要素をマーキングできます。

また、AttributeTargets の複数のインスタンスを渡すこともできます。 カスタム属性を任意のクラスやメソッドに適用できるように指定するコード片を次に示します。


[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]


Inherited プロパティ

Inherited プロパティは、属性が適用されるクラスから継承されるクラスが、その属性を継承できるかどうかを指定します。 このプロパティには、true (既定値) または false のいずれかのフラグが指定できます。 たとえば次のコード例では、MyAttributeInherited の値は既定値の true ですが、YourAttributeInherited の値は false です。


// This defaults to Inherited = true.
public class MyAttribute : Attribute
{
    //...
}

[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class YourAttribute : Attribute
{
    //...
}


2 つの属性は、基本クラス MyClass 内のメソッドに次のように適用されます。


public class MyClass
{
    [MyAttribute]
    [YourAttribute]
    public virtual void MyMethod()
    {
        //...
    }
}


最後に、基本クラス MyClass から YourClass クラスが継承されます。 メソッド MyMethod は、YourAttribute ではなく MyAttribute を示します。


public class YourClass : MyClass
{
    // MyMethod will have MyAttribute but not YourAttribute.
    public override void MyMethod()
    {
        //...
    }

}


AllowMultiple プロパティ

AllowMultiple プロパティは、1 つの要素に対して属性の複数のインスタンスが存在できるかどうかを示します。 このプロパティを true に設定すると、複数のインスタンスが存在でき、false (既定値) に設定すると、1 つのインスタンスだけが存在できます。

MyAttributeAllowMultiple の値が既定値の falseYourAttribute の値が true のコード例を次に示します。


//This defaults to AllowMultiple = false.
public class MyAttribute : Attribute
{
}

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class YourAttribute : Attribute
{
}


これらの属性の複数のインスタンスが適用されたとき、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()
    {
        //...
    }
}


AllowMultiple プロパティと Inherited プロパティの両方が true に設定されている場合は、あるクラスから派生したクラスは属性を継承でき、同じ子クラスに同じ属性が適用される別のインスタンスを持つことができます。 AllowMultiplefalse に設定されている場合は、親クラスでの属性の値が、子クラスにおける同じ属性の新しいインスタンスによって上書きされます。

AttributeUsageAttribute を適用した後で、属性の仕様を定義できます。 属性クラスの宣言は、次のコードに示すように、普通のクラスの宣言に似ています。


[AttributeUsage(AttributeTargets.Method)]
public class MyAttribute : Attribute
{
    // . . .
}


この属性定義では、次の点が示されています。

  • 属性クラスは、パブリック クラスとして宣言する必要があります。

  • 規則では、属性クラスの名前の最後は Attribute にします。 この規則は必須ではありませんが、クラス名をわかりやすくするために、この規則に従うことをお勧めします。 属性を適用するとき、「Attribute」は省略できます。

  • すべての属性クラスは、System.Attribute から直接または間接的に継承する必要があります。

  • Microsoft Visual Basic では、すべてのカスタム属性クラスが AttributeUsageAttribute 属性を持つ必要があります。

属性をコンストラクターで初期化する方法は、普通のクラスの場合と同じです。 次のコードは、一般的な属性のコンストラクターを示します。 このパブリック コンストラクターは 1 つのパラメーターをとり、メンバー変数と等しい値に設定します。


public MyAttribute(bool myvalue)
{
    this.myvalue = myvalue;
}


コンストラクターをオーバーロードすることによって、ほかの値の組み合わせを使用できます。 カスタム属性クラスのプロパティも定義すると、属性を初期化するときに、名前付きパラメーターと位置指定パラメーターの組み合わせを使用できます。 通常は、すべての必須パラメーターを位置指定パラメーターとして定義し、すべてのオプション パラメーターを名前付きパラメーターとして定義します。 この場合は、必須パラメーターがないと属性を初期化できません。 ほかのすべてのパラメーターはオプションです。 Visual Basic では、属性クラスのコンストラクターには ParamArray 引数を使用できません。

次のコードでは、前のコンストラクターを使用する属性を必須パラメーターとオプション パラメーターを使用して適用する方法を示します。 このコード例では、属性が、必須パラメーターとして 1 つのブール値を、オプション パラメーターとして 1 つの文字列プロパティを持つことを想定しています。


// 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
{
    //...
}


名前付きパラメーターを定義する場合、または属性によって格納される値を簡単に返す手段を用意する場合は、プロパティを宣言します。 属性のプロパティは、返されるデータ型の記述を持つパブリック エンティティとして宣言する必要があります。 プロパティの値を保持する変数を定義してから、それに get メソッドと set メソッドを関連付けます。 次のコードは、属性に簡単なプロパティを実装する方法を示します。


public bool MyProperty
{
    get {return this.myvalue;}
    set {this.myvalue = value;}
}


ここでは、ここまでの説明のまとめとして、コードのセクションの作成者についての情報を提供する簡単な属性のデザイン方法を示します。 この例における属性は、プログラマの名前とレベル、およびコードがレビューされたかどうかの情報を格納します。 属性は、3 つのプライベート変数を使用して、保存する実効値を格納します。 各変数は、値を取得および設定するパブリック プロパティによって表されます。 最後に、2 つの必須パラメーターを持つコンストラクターが定義されます。


[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;}
    }
}


この属性は、フルネーム DeveloperAttribute または省略名 Developer を使用して、次のいずれかの方法で適用できます。


[Developer("Joan Smith", "1")]

-or-

[Developer("Joan Smith", "1", Reviewed = true)]


最初の例は、名前付き必須パラメーターだけを使用して適用される属性です。2 番目の例は、必須パラメーターとオプション パラメーターの両方を使用して適用される属性です。

表示: