Zugriff auf benutzerdefinierte Attribute

Nachdem Attribute Programmierelementen zugeordnet worden sind, kann Reflektion benutzt werden, um deren Existenz und Werte abzufragen. .NET stellt den MetadataLoadContext-Kontext bereit, den Sie verwenden können, um Code zu untersuchen, der nicht zur Ausführung geladen werden kann.

MetadataLoadContext

Code, der in den MetadataLoadContext-Kontext geladen wurde, kann nicht ausgeführt werden. Das bedeutet, dass Instanzen von benutzerdefinierten Attributen nicht erstellt werden können, da dies die Ausführung deren Konstruktoren erfordern würde. Um benutzerdefinierte Attribute in den MetadataLoadContext-Kontext zu laden und zu untersuchen, verwenden Sie die CustomAttributeData-Klasse. Sie können Instanzen dieser Klasse abrufen, indem Sie die geeignete Überladung der statistischen CustomAttributeData.GetCustomAttributes-Methode verwenden. Weitere Informationen finden Sie unter Überprüfen von Assemblyinhalten mithilfe von MetadataLoadContext.

Der Ausführungskontext

Die wichtigsten Reflektionsmethoden zum Abfragen von Attributen im Ausführungskontext sind MemberInfo.GetCustomAttributes und Attribute.GetCustomAttributes.

Die Möglichkeit des Zugriffs auf ein benutzerdefiniertes Attribut wird unter Berücksichtigung der Assembly, der es angefügt ist, überprüft. Dies entspricht der Überprüfung, ob eine Methode auf einem Typ in der Assembly, in der das benutzerdefinierte Attribut angefügt ist, den Konstruktor des benutzerdefinierten Attributs aufrufen kann.

Methoden wie Assembly.GetCustomAttributes(Boolean) überprüfen die Sichtbarkeit und die Erreichbarkeit des Typarguments. Nur Code in der Assembly, die den benutzerdefinierten Typ enthält, kann ein benutzerdefiniertes Attribut dieses Typs mithilfe von GetCustomAttributes abrufen.

Das folgende C#-Beispiel ist ein typisches Entwurfsmuster eines benutzerdefinierten Attributs. Es stellt das Runtimemodell der Reflektion des benutzerdefinierten Attributs dar.

System.DLL
public class DescriptionAttribute : Attribute
{
}

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

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

Wenn die Runtime versucht, die benutzerdefinierten Attribute für den öffentlichen benutzerdefinierten Attributtyp DescriptionAttribute abzurufen, der an die GetLanguage-Methode angefügt ist, werden folgende Aktionen ausgeführt:

  1. Die Laufzeit überprüft, ob das Typargument DescriptionAttribute für Type.GetCustomAttributes(Type type) öffentlich ist und daher sichtbar ist und aufgerufen werden kann.
  2. Die Laufzeit überprüft, ob der benutzerdefinierte Typ MyDescriptionAttribute, der von DescriptionAttribute abgeleitet ist, innerhalb der Assembly System.Web.dll, wo er der GetLanguage()-Methode angefügt ist, sichtbar ist und aufgerufen werden kann.
  3. Die Runtime überprüft, ob der Konstruktor von MyDescriptionAttribute innerhalb der Assembly System.Web.DLL sichtbar ist und aufgerufen werden kann.
  4. Die Runtime ruft den Konstruktor von MyDescriptionAttribute mit den benutzerdefinierten Attributparametern auf und gibt dem Aufrufer das neue Objekt zurück.

Dem Reflektionsmodell des benutzerdefinierten Attributs könnten Instanzen von benutzerdefinierten Typen außerhalb der Assembly fehlen, in der der Typ definiert ist. Hier besteht kein Unterschied zu den Membern in der Runtimesystembibliothek, die Instanzen benutzerdefinierter Typen zurückgeben, z. B. die Type.GetMethods-Methode, die ein Array von RuntimeMethodInfo-Objekten zurückgibt. Um zu verhindern, dass ein Client Informationen über einen benutzerdefinierten Typ eines benutzerdefinierten Attributs ermittelt, definieren Sie, dass die Member des Typen nicht öffentlich sein sollen.

Das folgende Beispiel zeigt die einfachste Möglichkeit, Reflektion zu verwenden, um Zugriff auf benutzerdefinierte Attribute zu erhalten.

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

Weitere Informationen