Acesse atributos personalizados

Depois que os atributos tiverem sido associados aos elementos do programa, a reflexão poderá ser usada para consultar sua existência e seus valores. O .NET disponibiliza a classe MetadataLoadContext, que você pode usar para examinar o código que não pode ser carregado para execução.

MetadataLoadContext

O código carregado no contexto MetadataLoadContext não pode ser executado. Isso significa que instâncias de atributos personalizados não podem ser criadas porque isso exigiria a execução de seus construtores. Para carregar e analisar os atributos personalizados no contexto CustomAttributeData, use a classe MetadataLoadContext. Você pode obter as instâncias dessa classe usando a sobrecarga apropriada do método CustomAttributeData.GetCustomAttributes estático. Para mais informações, confira Como inspecionar o conteúdo do assembly usando MetadataLoadContext.

O contexto de execução

Os principais métodos de reflexão para consultar atributos no contexto de execução são MemberInfo.GetCustomAttributes e Attribute.GetCustomAttributes.

A acessibilidade de um atributo personalizado é verificada em relação ao assembly ao qual ele está anexado. Isso é equivalente a verificar se um método em um tipo no assembly no qual o atributo personalizado está anexado pode chamar o construtor do atributo personalizado.

Métodos como Assembly.GetCustomAttributes(Boolean) verificam a visibilidade e a acessibilidade do argumento de tipo. Somente o código no assembly que contém o tipo definido pelo usuário pode recuperar um atributo personalizado desse tipo usando GetCustomAttributes.

O exemplo de C# a seguir é um padrão de design de atributo personalizado típico. Ele ilustra o modelo de reflexão do atributo personalizado em runtime.

System.DLL
public class DescriptionAttribute : Attribute
{
}

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

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

Se o runtime estiver tentando recuperar os atributos personalizados para o tipo de atributo personalizado público DescriptionAttribute anexado ao método GetLanguage, ele executará as seguintes ações:

  1. O runtime verifica se o argumento de tipo DescriptionAttribute para Type.GetCustomAttributes(Type type) é público, e portanto está visível e acessível.
  2. O runtime verifica se o tipo definido pelo usuário MyDescriptionAttribute, que é derivado de DescriptionAttribute, está visível e acessível dentro do assembly System.Web.dll, onde está anexado ao método GetLanguage().
  3. O runtime verifica se o construtor de MyDescriptionAttribute está visível e acessível dentro do assembly System.Web.dll.
  4. O runtime chama o construtor de MyDescriptionAttribute com os parâmetros do atributo personalizado e retorna o novo objeto para o chamador.

O modelo de reflexão do atributo personalizado pode causar perda de instâncias de tipos definidos pelo usuário fora do assembly no qual o tipo é definido. Isso não é diferente dos membros no sistema da biblioteca runtime que retornam instâncias de tipos definidos pelo usuário, como Type.GetMethods que retorna uma matriz de objetos RuntimeMethodInfo. Para impedir que um cliente descubra informações sobre um tipo de atributo personalizado definido pelo usuário, defina os membros do tipo como confidenciais.

O exemplo a seguir demonstra a maneira básica de usar a reflexão para obter acesso a atributos personalizados.

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

Confira também