Поделиться через


Написание настраиваемых атрибутов

Обновлен: Ноябрь 2007

Чтобы создавать собственные настраиваемые атрибуты, совсем необязательно в совершенстве овладевать множеством новых понятий. Если вы имеете представление об объектно-ориентированном программировании и знаете, как создавать классы, то вы обладаете почти всеми нужными знаниями. Настраиваемые атрибуты, в сущности, представляют собой традиционные классы, прямо или косвенно наследующие от System.Attribute. Подобно традиционным классам, настраиваемые атрибуты содержат методы, хранящие и считывающие данные.

Вот основные этапы правильно выстроенного процесса разработки классов настраиваемых атрибутов.

  • Применение атрибута AttributeUsageAttribute

  • Объявление класса атрибута

  • Объявление конструкторов

  • Объявление свойств

В этом разделе описано каждое из этих действий; завершается он примером настраиваемого атрибута.

Применение атрибута AttributeUsageAttribute

Объявление настраиваемого атрибута начинается с атрибута AttributeUsageAttribute, определяющего некоторые ключевые характеристики класса атрибута. Например, есть возможность определить, может ли атрибут быть унаследован другими классами, или указать элементы языка, к которым может применяться этот атрибут. В следующем фрагменте кода показан пример использования атрибута AttributeUsageAttribute.

[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
<AttributeUsage(AttributeTargets.All, Inherited := False, AllowMultiple := true)>

В System.AttributeUsageAttribute имеется три члена, которые важны для создания настраиваемых атрибутов: AttributeTargets, Inherited, и AllowMultiple.

Член AttributeTargets

В предыдущем примере использовано значение AttributeTargets.All, показывающее, что этот атрибут может применяться к любым элементам программы. Можно также задать значение AttributeTargets.Class, показывающее, что атрибут может применяться только к классам, или AttributeTargets.Method, показывающее, что этот атрибут может применяться только к методам. Подобным образом с целью последующего описания с помощью настраиваемых атрибутов можно выделить любые элементы программы.

Также можно передать несколько экземпляров AttributeTargets. В следующем фрагменте кода разрешается применение настраиваемого атрибута к любому классу или методу.

[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)]
<AttributeUsage (AttributeTargets.Class Or AttributeTargets.Method)>

Свойство Inherited

Свойство Inherited указывает, может ли атрибут быть унаследован классами, производными от класса, к которому этот атрибут применен. Это свойство принимает значение true (по умолчанию) или false. Например, в следующем коде свойству Inherited атрибута MyAttribute задано значение по умолчанию, true, в то время как свойство Inherited атрибута YourAttribute имеет значение false.

//This defaults to Inherited = true.
public class MyAttribute :Attribute
{
}
[AttributeUsage( Inherited = false)]
public class YourAttribute : Attribute
{
}
<AttributeUsage( AttributeTargets.All, Inherited := True)> Public Class _
MyAttribute
    Inherits Attribute
End Class

<AttributeUsage( AttributeTargets.All, Inherited := False)> Public Class _
YourAttribute
    Inherits Attribute
End Class

Затем эти два атрибута применяются к методу в базовом классе MyClass.

public class MyClass
{
    [MyAttribute]
    [YourAttribute]
    public virtual void MyMethod() 
    {
        //...
    }
}
' In Microsoft Visual Basic, you apply multiple attributes
' by separating them with commas.
Public Class [MyClass]
    <MyAttribute, YourAttribute> Public Overridable Sub MyMethod()
        '...
    End Sub
End Class

Наконец, класс YourClass наследуется от базового класса MyClass. Метод MyMethod использует атрибут MyAttribute, а не YourAttribute.

public class YourClass: MyClass
{
      //MyMethod will have MyAttribute but not YourAttribute.
      public override void MyMethod()
      {
         //...
      }

}
Public Class YourClass
   Inherits [MyClass]
      'MyMethod will have MyAttribute but not YourAttribute.
      Public overrides Sub MyMethod()
         '...
      End Sub
End Class

Свойство AllowMultiple

Свойство AllowMultiple указывает, можно ли применять к элементу несколько экземпляров атрибута. Если его значение равно true, то существование нескольких экземпляров атрибута разрешено, если же оно равно false (по умолчанию), то можно использовать только один экземпляр.

В следующем примере кода свойство AllowMultiple атрибута MyAttribute имеет значение по умолчанию, false , в то время как для атрибута YourAttribute это свойство имеет значение true.

//This defaults to AllowMultiple = false.
public class MyAttribute :Attribute
{
}

[AttributeUsage(AllowMultiple = true)]
public class YourAttribute : Attribute
{
}
'This defaults to AllowMultiple = false.
<AttributeUsage(AttributeTargets.Method)> Public Class _
MyAttribute
    Inherits Attribute
End Class

<AttributeUsage(AttributeTargets.Method, AllowMultiple := True)> Public Class _
YourAttribute
    Inherits Attribute
End Class

При применении нескольких экземпляров этих атрибутов атрибут MyAttribute порождает ошибку компилятора. В следующем примере кода показано правильное использование атрибута YourAttribute и неправильное использование атрибута MyAttribute.

public class MyClass
{
    //This produces an error.
    //Duplicates are not allowed.
    [MyAttribute]
    [MyAttribute]
    public void MyMethod() {
        //...
    }

    //This is valid.
    [YourAttribute]
    [YourAttribute]
    public void YourMethod(){
    //...
    }
}
' In Microsoft Visual Basic you apply multiple attributes
' by separating them with commas.
Public Class [MyClass]
    'This produces an error.
    'Duplicates are not allowed.
    <MyAttribute, MyAttribute> Public Overridable Sub MyMethod()
        '...
    End Sub

    'This is valid.    
    <YourAttribute, YourAttribute> Public Sub YourMethod()
        '...
    End Sub
End Class

Если и свойство AllowMultiple, и свойство Inherited имеют значение true, то класс, наследуемый от другого класса, может наследовать атрибуты и иметь дополнительные экземпляры атрибута, применяемого в этом же дочернем классе. Если значение AllowMultiple равно false, то значения любых атрибутов в родительском классе будут переписаны новыми экземплярами того же самого атрибута в дочернем классе.

Объявление класса атрибута

После применения AttributeUsageAttribute можно начать работу над определением характеристик атрибута. Объявление класса атрибута выглядит аналогично объявлению традиционного класса, что показано в следующем коде.

public class MyAttribute : System.Attribute 
{
    // . . . 
}
' This attribute is only usable with methods
<AttributeUsage(AttributeTargets.Method)> Public Class MyAttribute
    Inherits System.Attribute
    ' . . . 
End Class

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

  • Классы атрибутов должны объявляться как открытые классы.

  • В соответствии с общепринятой практикой имя класса атрибута должно завершаться словом Attribute. Это условие не обязательно, но полезно для повышения удобства чтения. При применении атрибута использование слова "Attribute" не обязательно.

  • Все классы атрибутов должны непосредственно или косвенно наследовать от класса System.Attribute.

  • В Microsoft Visual Basic все классы настраиваемых атрибутов должны иметь атрибут AttributeUsageAttribute.

Объявление конструкторов

Атрибуты инициализируются с помощью конструкторов точно так же, как традиционные классы. В следующем примере кода показан типичный конструктор атрибута. Этот открытый конструктор получает параметр и присваивает его значение внутренней переменной.

public MyAttribute(bool myvalue)
{
    this.myvalue = myvalue;        
}
Public Sub New(newvalue As Boolean)
    Me.myvalue = newvalue
End Sub

Чтобы использовать различные сочетания параметров, можно выполнить перегрузку конструктора. Если для класса атрибута определяется также и свойство, то при инициализации атрибута можно использовать сочетание именованных и позиционных параметров. В обычном случае все обязательные параметры определяются как позиционные, а все необязательные — как именованные. В этом случае атрибут нельзя инициализировать без обязательного параметра. Все прочие параметры являются необязательными. Следует отметить, что в языке Visual Basic конструкторы классов атрибутов не могут использовать аргумент ParamArray.

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

//One required (positional) and one optional (named) parameter are applied.
[MyAttribute(false, OptionalParameter = "optional data")]
//One required (positional) parameter is applied.
[MyAttribute(false)]
'One required (positional) and one optional (named) parameter are applied.
<MyAttribute(False, OptionalParameter := "optional data")>
' ...
'One required (positional) parameter is applied.
<MyAttribute(False)>

Объявление свойств

Если необходимо определить именованный параметр или предоставить простой способ получения значений, хранящихся в атрибуте, то можно объявить свойство. Свойства атрибута следует объявлять как открытые сущности с описанием типа данных, которые они возвращают. Определите переменную, которая будет хранить значение свойства, и свяжите ее с методами get и set. В следующем примере кода показана реализация простого свойства атрибута.

public bool MyProperty
{
    get {return this.myvalue;}
    set {this.myvalue = value;}
}
Public Property MyProperty As Boolean
    Get
        Return Me.myvalue
    End Get
    Set
        Me.myvalue = value
    End Set
End Property

Пример настраиваемого атрибута

В этом разделе используются приведенные выше сведения и демонстрируется пример создания простого атрибута, содержащего сведения об авторе раздела кода. Атрибут в этом примере хранит имя и уровень программиста, а также данные об изменениях, внесенных в код. Для хранения текущих сохраняемых значений в нем используются три закрытые переменные. Каждая переменная представлена открытым свойством, которое возвращает и задает эти значения. Наконец, в примере определяется конструктор с двумя обязательными параметрами.

[AttributeUsage(AttributeTargets.All)]
public class DeveloperAttribute : System.Attribute 
{
        
    //Private fields.
    private string name;
    private string level;
    private bool reviewed;

    //This constructor defines two required parameters: name and level.

    public  DeveloperAttribute(string name,string level)
    {
        this.name = name;
        this.level = level; 
        this.reviewed = false;
    }

    //Define Name property.
    //This is a read-only attribute.
        
    public virtual string Name
    {
        get {return name;}        
    }

    //Define Level property.
    //This is a read-only attribute.
        
    public virtual string Level
    {
        get {return level;}
    }

    //Define Reviewed property. 
    //This is a read/write attribute. 

    public virtual bool Reviewed
    {
        get {return reviewed;}
    set {reviewed = value;}
    }
}
<AttributeUsage(AttributeTargets.All)> Public Class DeveloperAttribute
    Inherits System.Attribute
    
    'Private fields.
    Private m_name As String
    Private m_level As String
    Private m_reviewed As Boolean    
    
    'This constructor defines two required parameters: name and level.
    Public Sub New(name As String, level As String)
        Me.m_name = name
        Me.m_level = level
        Me.m_reviewed = False
    End Sub
    
    'Define Name property.
    'This is a read-only attribute.    
    Public Overridable ReadOnly Property Name() As String
        Get
            Return m_name
        End Get
    End Property 
    
    'Define Level property.
    'This is a read-only attribute.    
    Public Overridable ReadOnly Property Level() As String
        Get
            Return m_level
        End Get
    End Property
    
    'Define Reviewed property. 
    'This is a read/write attribute.    
    Public Overridable Property Reviewed() As Boolean
        Get
            Return m_reviewed
        End Get
        Set
            m_reviewed = value
        End Set
    End Property
End Class

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

[Developer("Joan Smith", "1")]
[Developer("Joan Smith", "1", Reviewed = true)]
<Developer("Joan Smith", "1")>
<Developer("Joan Smith", "1", Reviewed := True)>

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

См. также

Ссылки

System.Attribute

AttributeUsageAttribute

Другие ресурсы

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