カスタム属性にアクセスする

属性がプログラム要素に関連付けられると、リフレクションを使用して、その存在と値をクエリすることができます。 .NET では MetadataLoadContext が提供されており、これを使用して、実行時に読み込まれないコードを検証することができます。

MetadataLoadContext

MetadataLoadContext コンテキストに読み込まれたコードは、実行することができません。 つまり、コンストラクターを実行する必要があるため、カスタム属性のインスタンスは作成できないということです。 MetadataLoadContext コンテキストにカスタム属性を読み込み、検証するには、CustomAttributeData クラスを使用します。 静的な CustomAttributeData.GetCustomAttributes メソッドの適切なオーバーロードを使用して、このクラスのインスタンスを取得できます。 詳しくは、「方法: MetadataLoadContext を使用してアセンブリの内容を検査する」をご覧ください。

実行コンテキスト

実行コンテキストの属性をクエリする主なリフレクション メソッドは、MemberInfo.GetCustomAttributesAttribute.GetCustomAttributes です。

カスタム属性のアクセシビリティは、添付されているアセンブリに関してチェックされます。 これは、カスタム属性が添付されているアセンブリの型のメソッドが、カスタム属性のコンストラクターを呼び出すことができるかどうかをチェックするのと同じです。

Assembly.GetCustomAttributes(Boolean) などのメソッドは、型引数の可視性とアクセシビリティをチェックします。 ユーザー定義型を含むアセンブリのコードのみが、GetCustomAttributes を使用する型のカスタム属性を取得することができます。

次の C# の例は、一般的なカスタム属性の設計パターンです。 これは、ランタイムのカスタム属性のリフレクション モデルを示しています。

System.DLL
public class DescriptionAttribute : Attribute
{
}

System.Web.DLL
internal class MyDescriptionAttribute : DescriptionAttribute
{
}

public class LocalizationExtenderProvider
{
    [MyDescriptionAttribute(...)]
    public CultureInfo GetLanguage(...)
    {
    }
}

このランタイムで GetLanguage メソッドに添付されている公開のカスタム属性の型 DescriptionAttribute のカスタム属性を取得しようとしている場合、次のアクションが実行されます。

  1. ランタイムは、Type.GetCustomAttributes(Type type) に対する型引数 DescriptionAttribute が公開であるため、表示およびアクセスできることをチェックします。
  2. ランタイムは、DescriptionAttribute から派生するユーザー定義型 MyDescriptionAttribute が System.Web.dll アセンブリ内で表示およびアクセスできることをチェックします。これは、メソッド GetLanguage() に添付されている場所です。
  3. ランタイムは、MyDescriptionAttribute のコンストラクターが、System.Web.dll アセンブリ内で表示およびアクセスできることをチェックします。
  4. ランタイムは、カスタム属性のパラメータを使って MyDescriptionAttribute のコンストラクターを呼び出し、呼び出し元に新しいオブジェクトを返します。

カスタム属性のリフレクション モデルは、型が定義されているアセンブリの外にあるユーザー定義型のインスタンスをリークする可能性があります。 これは、RuntimeMethodInfo オブジェクトの配列を返す Type.GetMethods など、ユーザー定義型のインスタンスを返すランタイム システム ライブラリのメンバーと同様です。 クライアントがユーザー定義のカスタム属性の型に関する情報を検出できないようにするには、型のメンバーを非公開に定義します。

次の例では、カスタム属性にアクセスできるリフレクションを使用する基本的な方法を示します。

using namespace System;

public ref class ExampleAttribute : Attribute
{
private:
    String^ stringVal;

public:
    ExampleAttribute()
    {
        stringVal = "This is the default string.";
    }


    property String^ StringValue
    {
        String^ get() { return stringVal; }
        void set(String^ value) { stringVal = value; }
    }
};

[Example(StringValue="This is a string.")]
public ref class Class1
{
public:
    static void Main()
    {
        System::Reflection::MemberInfo^ info = Type::GetType("Class1");
        for each (Object^ attrib in info->GetCustomAttributes(true))
        {
            Console::WriteLine(attrib);
        }
    }
};

int main()
{
    Class1::Main();
}
using System;

public class ExampleAttribute : Attribute
{
    private string stringVal;

    public ExampleAttribute()
    {
        stringVal = "This is the default string.";
    }

    public string StringValue
    {
        get { return stringVal; }
        set { stringVal = value; }
    }
}

[Example(StringValue="This is a string.")]
class Class1
{
    public static void Main()
    {
        System.Reflection.MemberInfo info = typeof(Class1);
        foreach (object attrib in info.GetCustomAttributes(true))
        {
            Console.WriteLine(attrib);
        }
    }
}
Public Class ExampleAttribute
    Inherits Attribute

    Private stringVal As String

    Public Sub New()
        stringVal = "This is the default string."
    End Sub

    Public Property StringValue() As String
        Get
            Return stringVal
        End Get
        Set(Value As String)
            stringVal = Value
        End Set
    End Property
End Class

<Example(StringValue:="This is a string.")> _
Class Class1
    Public Shared Sub Main()
        Dim info As System.Reflection.MemberInfo = GetType(Class1)
        For Each attrib As Object In info.GetCustomAttributes(true)
            Console.WriteLine(attrib)
        Next attrib
    End Sub
End Class

関連項目