Шрифт:
// Старая серая лошадка, она уже не та...
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
// -------------------------------------------------------
// CustomAttribute Type: 06000005
// CustomAttributeName: AttributedCarLibrary.VehicleDescriptionAttribute :: instance void
.ctor(class System.String)
// Length: 45
// Value : 01 00 28 41 20 76 65 72 79 20 6c 6f 6e 67 2c 20 > (A very long, <
// : 73 6c 6f 77 2c 20 62 75 74 20 66 65 61 74 75 72 >slow, but feature<
// : 65 2d 72 69 63 68 20 61 75 74 6f 00 00 >e-rich auto <
// ctor args: ("A very long, slow, but feature-rich auto")
Ограничение использования атрибутов
По умолчанию специальные атрибуты могут быть применены практически к любому аспекту кода (методам, классам, свойствам и т.д.). Таким образом, если бы это имело смысл, то
VehicleDescription
можно было бы использовать для уточнения методов, свойств или полей (помимо прочего):
[VehicleDescription("A very long, slow, but feature-rich auto")]
public class Winnebago
{
[VehicleDescription("My rocking CD player")]
public void PlayMusic(bool On)
{
...
}
}
В одних случаях такое поведение является точно таким, какое требуется, но в других может возникнуть желание создать специальный атрибут, применяемый только к избранным элементам кода. Чтобы ограничить область действия специального атрибута, понадобится добавить к его определению атрибут
[AttributeUsage]
, который позволяет предоставлять любую комбинацию значений (посредством операции "ИЛИ") из перечисления AttributeTargets
:
// Это перечисление определяет возможные целевые элементы для атрибута.
public enum AttributeTargets
{
All, Assembly, Class, Constructor,
Delegate, Enum, Event, Field, GenericParameter,
Interface, Method, Module, Parameter,
Property, ReturnValue, Struct
}
Кроме того, атрибут
[AttributeUsage]
допускает необязательную установку именованного свойства(AllowMultiple
), которое указывает, может ли атрибут применяться к тому же самому элементу более одного раза (стандартным значением является false
). Вдобавок [AttributeUsage]
разрешает указывать, должен ли атрибут наследоваться производными классами, с использованием именованного свойства Inherited
(со стандартным значением true
). Модифицируйте определение
VehicleDescriptionAttribute
для указания на то, что атрибут [VehicleDescription]
может применяться только к классу или структуре:
// На этот раз для аннотирования специального атрибута
// используется атрибут AttributeUsage.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false)]
public sealed class VehicleDescriptionAttribute : System.Attribute