访问自定义属性

特性与程序元素相关联后,可使用反射来查询它们是否存在以及它们的值。 .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

另请参阅