Глава.18 .Настраиваемые.атрибуты
атрибутов в этих скобках через запятую. Если конструктор класса атрибута не
имеет параметров, круглые скобки можно опустить. Ну и, как уже упоминалось,
суффикс
Attribute
также является необязательным. Показанные далее строки
приводят к одному и тому же результату и демонстрируют все возможные способы
применения набора атрибутов:
[Serializable][Flags]
[Serializable, Flags]
[FlagsAttribute, SerializableAttribute]
[FlagsAttribute()][Serializable()]
Определение класса атрибутов
Вы уже знаете, что любой атрибут представляет собой экземпляр класса, производ-
ного от
System.Attribute
, и умеете применять атрибуты. Пришло время рассмо-
треть процесс их создания. Представьте, что вы работаете в Microsoft и получили
задание реализовать поддержку битовых флагов в перечислимых типах. Для начала
нужно определить класс
FlagsAttribute
:
namespace System {
public class FlagsAttribute : System.Attribute {
public FlagsAttribute() {
}
}
}
Обратите внимание, что класс
FlagsAttribute
наследует от класса
Attribute
;
именно это делает его CLS-совместимым. Вдобавок в имени класса присутствует
суффикс
Attribute
. Это соответствует стандарту именования, хотя и не является
обязательным. Наконец, все неабстрактные атрибуты должны содержать хотя бы
один открытый конструктор. Простейший конструктор
FlagsAttribute
не имеет
параметров и не выполняет никаких действий.
ВниМание
Атрибут.следует.рассматривать.как.логический.контейнер.состояния .Иначе.гово-
ря,.хотя.атрибут.и.является.классом,.этот.класс.должен.быть.крайне.простым .Он.
должен.содержать.всего.один.открытый.конструктор,.принимающий.обязательную.
(или.позиционную).информацию.о.состоянии.атрибута .Также.класс.может.содер-
жать.открытые.поля/свойства,.принимающие.дополнительную.(или.именованную).
информацию.о.состоянии.атрибута .В.классе.не.должно.быть.открытых.методов,.
событий.или.других.членов
В.общем.случае.я.не.одобряю.использование.открытых.полей .Атрибутов.это.тоже.
касается .Лучше.воспользоваться.свойствами,.так.как.они.обеспечивают.большую.
гибкость.в.случаях,.когда.требуется.внести.изменения.в.реализацию.класса.атри-
бутов
469
Определение.класса.атрибутов
Получается, что экземпляры класса
FlagsAttribute
можно применять к чему
угодно, хотя реально этот атрибут следует применять только к перечислимым ти-
пам. Нет смысла применять его к свойству или методу. Чтобы указать компилятору
область действия атрибута, применим к классу атрибута экземпляр класса
System.
AttributeUsageAttribute
:
namespace System {
[AttributeUsage(AttributeTargets.Enum, Inherited = false)]
public class FlagsAttribute : System.Attribute {
public FlagsAttribute() {
}
}
}
В этой новой версии экземпляр
AttributeUsageAttribute
применяется к атри-
буту. В конце концов, атрибуты — это всего лишь классы, а значит, к ним, в свою
очередь, можно применять другие атрибуты. Атрибут
AttributeUsage
является
простым классом, указывающим компилятору область действия настраиваемого
атрибута. Все компиляторы имеют встроенную поддержку этого атрибута и при
попытке применить его к недопустимому элементу выдают сообщение об ошибке.
В рассматриваемом примере атрибут
AttributeUsage
указывает, что экземпляры
атрибута
Flags
работают только с перечислимыми типами.
Так как все атрибуты являются типами, понять, как устроен класс
AttributeUsageAttribute
, несложно. Вот исходный код этого класса в FCL:
[Serializable]
[AttributeUsage(AttributeTargets.Class, Inherited=true)]
public sealed class AttributeUsageAttribute : Attribute {
internal static AttributeUsageAttribute Default =
new AttributeUsageAttribute(AttributeTargets.All);
internal Boolean m_allowMultiple = false;
internal AttributeTargets m_attributeTarget = AttributeTargets.All;
internal Boolean m_inherited = true;
// Единственный открытый конструктор
public AttributeUsageAttribute(AttributeTargets validOn) {
m_attributeTarget = validOn;
}
internal AttributeUsageAttribute(AttributeTargets validOn,
Boolean allowMultiple, Boolean inherited) {
m_attributeTarget = validOn;
m_allowMultiple = allowMultiple;
m_inherited = inherited;
}
public Boolean AllowMultiple {
get { return m_allowMultiple; }
set { m_allowMultiple = value; }
}
продолжение
470
Do'stlaringiz bilan baham: |