Извлечение информации, сохраненной в атрибуте

Извлечение пользовательского атрибута — достаточно простой процесс. Сначала утвердите экземпляр атрибута, который необходимо извлечь. Затем используйте метод Attribute.GetCustomAttribute, чтобы инициализировать новый атрибут для значения извлекаемого атрибута. После инициализации нового атрибута для получения его значений просто используйте его свойства.

Важное примечаниеВажно

В этом разделе описывается процесс извлечения атрибутов для кода, загруженного в контекст выполнения.Чтобы извлечь атрибуты для кода, который загружен в контекст только для отражения, необходимо использовать класс CustomAttributeData, как показано в разделе Практическое руководство. Загрузка сборок в контекст, предназначенный только для отражения.

В этом разделе описаны следующие способы извлечения атрибутов:

  • Извлечение единственного экземпляра атрибута

  • Извлечение нескольких экземпляров атрибута, применяемых к одной области

  • Извлечение нескольких экземпляров атрибута, применяемых к разным областям

Извлечение единственного экземпляра атрибута

В следующем примере атрибут DeveloperAttribute (описанный в предыдущем разделе) применяется к классу MainApp на уровне класса. Метод GetAttribute использует GetCustomAttribute для извлечения значений, хранящихся в DeveloperAttribute на уровне класса, перед отображением их на консоли.

Imports System
Imports System.Reflection
Imports CustomCodeAttributes

<Developer("Joan Smith", "42", Reviewed := True)>
Class MainApp
    Public Shared Sub Main()
        ' Call function to get and display the attribute.
        GetAttribute(GetType(MainApp))
    End Sub

    Public Shared Sub GetAttribute(t As Type)
        ' Get instance of the attribute.
        Dim MyAttribute As DeveloperAttribute =
            CType(Attribute.GetCustomAttribute(t, GetType(DeveloperAttribute)), DeveloperAttribute)

        If MyAttribute Is Nothing Then
            Console.WriteLine("The attribute was not found.")
        Else
            ' Get the Name value.
            Console.WriteLine("The Name Attribute is: {0}." , MyAttribute.Name)
            ' Get the Level value.
            Console.WriteLine("The Level Attribute is: {0}." , MyAttribute.Level)
            ' Get the Reviewed value.
            Console.WriteLine("The Reviewed Attribute is: {0}." , MyAttribute.Reviewed)
        End If
    End Sub
End Class
using System;
using System.Reflection;
using CustomCodeAttributes;

[Developer("Joan Smith", "42", Reviewed = true)]
class MainApp
{
    public static void Main()
    {
        // Call function to get and display the attribute.
        GetAttribute(typeof(MainApp));
    }

    public static void GetAttribute(Type t)
    {
        // Get instance of the attribute.
        DeveloperAttribute MyAttribute =
            (DeveloperAttribute) Attribute.GetCustomAttribute(t, typeof (DeveloperAttribute));

        if (MyAttribute == null)
        {
            Console.WriteLine("The attribute was not found.");
        }
        else
        {
            // Get the Name value.
            Console.WriteLine("The Name Attribute is: {0}." , MyAttribute.Name);
            // Get the Level value.
            Console.WriteLine("The Level Attribute is: {0}." , MyAttribute.Level);
            // Get the Reviewed value.
            Console.WriteLine("The Reviewed Attribute is: {0}." , MyAttribute.Reviewed);
        }
    }
}
using namespace System;
using namespace System::Reflection;
using namespace CustomCodeAttributes;

[Developer("Joan Smith", "42", Reviewed = true)]
ref class MainApp
{
public:
    static void Main()
    {
        // Call function to get and display the attribute.
        GetAttribute(MainApp::typeid);
    }

    static void GetAttribute(Type^ t)
    {
        // Get instance of the attribute.
        DeveloperAttribute^ MyAttribute =
            (DeveloperAttribute^) Attribute::GetCustomAttribute(t, DeveloperAttribute::typeid);

        if (MyAttribute == nullptr)
        {
            Console::WriteLine("The attribute was not found.");
        }
        else
        {
            // Get the Name value.
            Console::WriteLine("The Name Attribute is: {0}." , MyAttribute->Name);
            // Get the Level value.
            Console::WriteLine("The Level Attribute is: {0}." , MyAttribute->Level);
            // Get the Reviewed value.
            Console::WriteLine("The Reviewed Attribute is: {0}." , MyAttribute->Reviewed);
        }
    }
};

При выполнении этой программы выводится следующий текст.

The Name Attribute is: Joan Smith.
The Level Attribute is: 42.
The Reviewed Attribute is: True.

Если атрибут не найден, то метод GetCustomAttribute инициализирует MyAttribute в значение null. В этом примере выполняется проверка MyAttribute на существование такого экземпляра, и пользователь получает уведомление в случае, если атрибут не найден. Если DeveloperAttribute не найден в области класса, то на консоль выводится следующее сообщение.

The attribute was not found. 

В этом примере предполагается, что атрибут определен в текущем пространстве имен. Если пространство имен не текущее, то необходимо импортировать то пространство имен, в котором хранится определение данного атрибута.

Извлечение нескольких экземпляров атрибута, применяемых к одной области

В предыдущем примере проверяемый класс и определенный искомый атрибут передаются в GetCustomAttribute. Этот код хорошо работает только в том случае, когда только один экземпляр атрибута применяется на уровне класса. Однако если на уровне одного и того же класса применяются несколько экземпляров атрибута, то метод GetCustomAttribute не сможет извлечь все данные. В случаях, когда несколько экземпляров одного атрибута применяются к одной области, можно использовать Attribute.GetCustomAttributes, чтобы поместить все экземпляры атрибута в массив. Например, если два экземпляра DeveloperAttribute применяются на уровне класса к одному и тому же классу, то метод GetAttribute может измениться таким образом, чтобы он отображал все данные, найденные в обоих атрибутах. Помните, чтобы применить несколько атрибутов на одном уровне, атрибут должен быть определен со значением свойства AllowMultiple заданным true в AttributeUsageAttribute.

В следующем примере показано, как использовать метод GetCustomAttributes для создания массива, ссылающегося на все экземпляры DeveloperAttribute в любом заданном классе. Значения всех атрибутов затем отображаются на консоли.

Public Shared Sub GetAttribute(t As Type)
    Dim MyAttributes() As DeveloperAttribute =
        CType(Attribute.GetCustomAttributes(t, GetType(DeveloperAttribute)), DeveloperAttribute())

    If MyAttributes Is Nothing Then
        Console.WriteLine("The attribute was not found.")
    Else
        For i As Integer = 0 To MyAttributes.Length - 1
            ' Get the Name value.
            Console.WriteLine("The Name Attribute is: {0}." , MyAttributes(i).Name)
            ' Get the Level value.
            Console.WriteLine("The Level Attribute is: {0}." , MyAttributes(i).Level)
            ' Get the Reviewed value.
            Console.WriteLine("The Reviewed Attribute is: {0}.", MyAttributes(i).Reviewed)
        Next i
    End If
End Sub
public static void GetAttribute(Type t)
{
    DeveloperAttribute[] MyAttributes =
        (DeveloperAttribute[]) Attribute.GetCustomAttributes(t, typeof (DeveloperAttribute));

    if (MyAttributes == null)
    {
        Console.WriteLine("The attribute was not found.");
    }
    else
    {
        for (int i = 0 ; i < MyAttributes.Length ; i++)
        {
            // Get the Name value.
            Console.WriteLine("The Name Attribute is: {0}." , MyAttributes[i].Name);
            // Get the Level value.
            Console.WriteLine("The Level Attribute is: {0}." , MyAttributes[i].Level);
            // Get the Reviewed value.
            Console.WriteLine("The Reviewed Attribute is: {0}.", MyAttributes[i].Reviewed);
        }
    }
}
public:
    static void GetAttribute(Type^ t)
    {
        array<DeveloperAttribute^>^ MyAttributes =
            (array<DeveloperAttribute^>^) Attribute::GetCustomAttributes(t, DeveloperAttribute::typeid);

        if (MyAttributes == nullptr)
        {
            Console::WriteLine("The attribute was not found.");
        }
        else
        {
            for (int i = 0 ; i < MyAttributes->Length; i++)
            {
                // Get the Name value.
                Console::WriteLine("The Name Attribute is: {0}." , MyAttributes[i]->Name);
                // Get the Level value.
                Console::WriteLine("The Level Attribute is: {0}." , MyAttributes[i]->Level);
                // Get the Reviewed value.
                Console::WriteLine("The Reviewed Attribute is: {0}.", MyAttributes[i]->Reviewed);
            }
        }
    }

Если атрибутов не найдено, то код уведомляет пользователя. В противном случае отображаются сведения, содержащиеся в обоих экземплярах DeveloperAttribute.

Извлечение нескольких экземпляров атрибута, применяемых к разным областям

Методы GetCustomAttributes и GetCustomAttribute не осуществляют поиск по всему классу и не возвращают все экземпляры атрибута в данном классе. Они ищут только один заданный метод или член одновременно. Если имеется класс с одним атрибутом, применяемый к каждому члену, и необходимо извлечь значения всех атрибутов, применяемых к этим членам, то следует поставлять по-отдельности каждый метод или член в GetCustomAttributes и GetCustomAttribute.

В следующем примере кода класс используется как параметр и выполняется поиск атрибута DeveloperAttribute (определенного ранее) на уровне класса и в каждом отдельном методе этого класса.

Public Shared Sub GetAttribute(t As Type)
    Dim att As DeveloperAttribute

    ' Get the class-level attributes.

    ' Put the instance of the attribute on the class level in the att object.
    att = CType(Attribute.GetCustomAttribute(t, GetType(DeveloperAttribute)), DeveloperAttribute)

    If att Is Nothing
        Console.WriteLine("No attribute in class {0}.\n", t.ToString())
    Else
        Console.WriteLine("The Name Attribute on the class level is: {0}.", att.Name)
        Console.WriteLine("The Level Attribute on the class level is: {0}.", att.Level)
        Console.WriteLine("The Reviewed Attribute on the class level is: {0}.\n", att.Reviewed)
    End If

    ' Get the method-level attributes.

    ' Get all methods in this class, and put them
    ' in an array of System.Reflection.MemberInfo objects.
    Dim MyMemberInfo() As MemberInfo = t.GetMethods()

    ' Loop through all methods in this class that are in the
    ' MyMemberInfo array.
    For i As Integer = 0 To MyMemberInfo.Length - 1
        att = CType(Attribute.GetCustomAttribute(MyMemberInfo(i), _
            GetType(DeveloperAttribute)), DeveloperAttribute)
        If att Is Nothing Then
            Console.WriteLine("No attribute in member function {0}.\n" , MyMemberInfo(i).ToString())
        Else
            Console.WriteLine("The Name Attribute for the {0} member is: {1}.",
                MyMemberInfo(i).ToString(), att.Name)
            Console.WriteLine("The Level Attribute for the {0} member is: {1}.",
                MyMemberInfo(i).ToString(), att.Level)
            Console.WriteLine("The Reviewed Attribute for the {0} member is: {1}.\n",
                MyMemberInfo(i).ToString(), att.Reviewed)
        End If
    Next
End Sub
public static void GetAttribute(Type t)
{
    DeveloperAttribute att;

    // Get the class-level attributes.

    // Put the instance of the attribute on the class level in the att object.
    att = (DeveloperAttribute) Attribute.GetCustomAttribute (t, typeof (DeveloperAttribute));

    if (att == null)
    {
        Console.WriteLine("No attribute in class {0}.\n", t.ToString());
    }
    else
    {
        Console.WriteLine("The Name Attribute on the class level is: {0}.", att.Name);
        Console.WriteLine("The Level Attribute on the class level is: {0}.", att.Level);
        Console.WriteLine("The Reviewed Attribute on the class level is: {0}.\n", att.Reviewed);
    }

    // Get the method-level attributes.

    // Get all methods in this class, and put them
    // in an array of System.Reflection.MemberInfo objects.
    MemberInfo[] MyMemberInfo = t.GetMethods();

    // Loop through all methods in this class that are in the
    // MyMemberInfo array.
    for (int i = 0; i < MyMemberInfo.Length; i++)
    {
        att = (DeveloperAttribute) Attribute.GetCustomAttribute(MyMemberInfo[i], typeof (DeveloperAttribute));
        if (att == null)
        {
            Console.WriteLine("No attribute in member function {0}.\n" , MyMemberInfo[i].ToString());
        }
        else
        {
            Console.WriteLine("The Name Attribute for the {0} member is: {1}.",
                MyMemberInfo[i].ToString(), att.Name);
            Console.WriteLine("The Level Attribute for the {0} member is: {1}.",
                MyMemberInfo[i].ToString(), att.Level);
            Console.WriteLine("The Reviewed Attribute for the {0} member is: {1}.\n",
                MyMemberInfo[i].ToString(), att.Reviewed);
        }
    }
}
public:
    static void GetAttribute(Type^ t)
    {
        DeveloperAttribute^ att;

        // Get the class-level attributes.

        // Put the instance of the attribute on the class level in the att object.
        att = (DeveloperAttribute^) Attribute::GetCustomAttribute (t, DeveloperAttribute::typeid);

        if (att == nullptr)
        {
            Console::WriteLine("No attribute in class {0}.\n", t->ToString());
        }
        else
        {
            Console::WriteLine("The Name Attribute on the class level is: {0}.", att->Name);
            Console::WriteLine("The Level Attribute on the class level is: {0}.", att->Level);
            Console::WriteLine("The Reviewed Attribute on the class level is: {0}.\n", att->Reviewed);
        }

        // Get the method-level attributes.

        // Get all methods in this class, and put them
        // in an array of System.Reflection.MemberInfo objects.
        array<MemberInfo^>^ MyMemberInfo = t->GetMethods();

        // Loop through all methods in this class that are in the
        // MyMemberInfo array.
        for (int i = 0; i < MyMemberInfo->Length; i++)
        {
            att = (DeveloperAttribute^) Attribute::GetCustomAttribute(MyMemberInfo[i], DeveloperAttribute::typeid);
            if (att == nullptr)
            {
                Console::WriteLine("No attribute in member function {0}.\n" , MyMemberInfo[i]->ToString());
            }
            else
            {
                Console::WriteLine("The Name Attribute for the {0} member is: {1}.",
                    MyMemberInfo[i]->ToString(), att->Name);
                Console::WriteLine("The Level Attribute for the {0} member is: {1}.",
                    MyMemberInfo[i]->ToString(), att->Level);
                Console::WriteLine("The Reviewed Attribute for the {0} member is: {1}.\n",
                    MyMemberInfo[i]->ToString(), att->Reviewed);
            }
        }
    }

Если на уровне метода или класса экземпляры DeveloperAttribute не найдены, то метод GetAttribute уведомляет пользователя о том, что атрибуты не найдены, и отображает имя метода или класса, не содержащего данный атрибут. Если атрибут найден, то поля Name, Level и Reviewed выводятся на консоль.

Члены класса Type можно использовать для получения отдельных методов и членов переданного класса. В этом примере для получения данных атрибута на уровне класса сначала запрашивается объект Type. Затем он использует Type.GetMethods для расположения экземпляров всех методов в массиве объектов System.Reflection.MemberInfo для получения сведений об атрибутах на уровне метода. Можно также использовать метод Type.GetProperties для проверки атрибутов на уровне свойства или метод Type.GetConstructors для проверки атрибутов на уровне конструктора.

См. также

Ссылки

System.Type

Attribute.GetCustomAttribute

Attribute.GetCustomAttributes

Основные понятия

Расширение метаданных с помощью атрибутов