В идеальном случае к настоящему моменту вы уже должны понимать перечисленные ниже ключевые моменты, касающиеся атрибутов .NET Core:
• атрибуты представляют собой классы, производные от
System.Attribute
;
• атрибуты дают в результате встроенные метаданные;
• атрибуты в основном бесполезны до тех пор, пока другой агент не проведет в их отношении рефлексию;
• атрибуты в языке C# применяются с использованием квадратных скобок.
А теперь давайте посмотрим, как реализовывать собственные специальные атрибуты и создавать специальное программное обеспечение, которое выполняет рефлексию по встроенным метаданным.
Построение специальных атрибутов
Первый шаг при построении специального атрибута предусматривает создание нового класса, производного от
System.Attribute
. Не отклоняясь от автомобильной темы, повсеместно встречающейся в книге, создайте новый проект типа
Class Library (Библиотека классов) на C# под названием
AttributedCarLibrary
. В этой сборке будет определено несколько классов для представления транспортных средств, каждый из которых описан с использованием специального атрибута по имени
VehicleDescriptionAttribute
:
using System;
// Специальный атрибут.
public sealed class VehicleDescriptionAttribute :Attribute
{
public string Description { get; set; }
public VehicleDescriptionAttribute(string description)
=> Description = description;
public VehicleDescriptionAttribute(){ }
}
Как видите, класс
VehicleDescriptionAttribute
поддерживает фрагмент строковых данных, которым можно манипулировать с помощью автоматического свойства (
Description
). Помимо того факта, что данный класс является производным от
System.Attribute
, ничего примечательного в его определении нет.
На заметку! По причинам, связанным с безопасностью, установившейся практикой в .NET Core считается проектирование всех специальных атрибутов как запечатанных. На самом деле среды Visual Studio и Visual Studio Code предлагают фрагмент кода под названием
Attribute
, который позволяет сгенерировать в окне редактора кода новый класс, производный от
System.Attribute
. Для раскрытия любого фрагмента кода необходимо набрать его имя и нажать клавишу <
ТаЬ> (один раз в Visual Studio Code и два раза в Visual Studio).
Применение специальных атрибутов
С учетом того, что класс
VehicleDescriptionAttribute
является производным от
System.Attribute
, теперь можно аннотировать транспортные средства. В целях тестирования добавьте в новую библиотеку классов следующие файлы классов:
// Motorcycle.cs
namespace AttributedCarLibrary
{
// Назначить описание с помощью "именованного свойства".
[Serializable]
[VehicleDescription(Description = "My rocking Harley")]
// Мой покачивающийся Харли
public class Motorcycle
{
}
// HorseAndBuggy.cs
namespace AttributedCarLibrary
{
[Serializable]
[Obsolete ("Use another vehicle!")]
[VehicleDescription("The old gray mare, she ain't what she used to be...")]
// Старая серая лошадка, она уже не та...
public class HorseAndBuggy
{
}
}
// Winnebago.cs
namespace AttributedCarLibrary
{
[VehicleDescription("A very long, slow, but feature-rich auto")]
// Очень длинный, медленный, но обладающий высокими
// техническими характеристиками автомобиль
public class Winnebago
{
}
}
Синтаксис именованных свойств
Обратите внимание, что классу
Motorcycle
назначается описание с использованием нового фрагмента синтаксиса, связанного с атрибутами, который называется
именованным свойством. В конструкторе первого атрибута
[VehicleDescription]
лежащие в основе строковые данные устанавливаются с применением свойства
Description
. Когда внешний агент выполнит рефлексию для этого атрибута, свойству
Description
будет передано указанное значение (синтаксис именованных свойств разрешен, только если атрибут предоставляет поддерживающее запись свойство .NET Core).
По контрасту для типов
HorseAndBuggy
и
Winnebago
синтаксис именованных свойств не используется, а строковые данные просто передаются через специальный конструктор. В любом случае после компиляции сборки
AttributedCarLibrary
с помощью утилиты
ildasm.exe
можно просмотреть добавленные описания метаданных. Например, ниже показано встроенное описание класса
Winnebago
:
// CustomAttribute #1
// -------------------------------------------------------