Codificando Atributos Personalizados
Para criar seus próprios atributos personalizados, você não precisa dominar muitos novos conceitos. Se você estiver familiarizado com programação orientada a objetos e sabe como criar classes, você já tem a maioria do conhecimento necessário. Atributos personalizados são classes essencialmente tradicionais que derivam de System.Attribute direta ou indiretamente. Exatamente como classes tradicionais, os atributos personalizados contêm métodos que armazenam e recuperam dados.
As etapas principais para criar corretamente classes de atributos personalizados são:
Aplicando o AttributeUsageAttribute
Declarar a classe de atributos
Declarar os construtores
Declarando propriedades
Esta seção descreve cada uma dessas etapas e termina com uma o exemplo de atributo personalizado.
Aplicando o AttributeUsageAttribute
Uma declaração de atributo personalizado começa com o AttributeUsageAttribute, que define algumas das principais características de chave de sua classe de atributos. Por exemplo, você pode especificar se o atributo pode ser herdado por outras classes ou especificar a quais elementos o atributo pode ser aplicado. O fragmento de código a seguir demonstra como usar a AttributeUsageAttribute .
<AttributeUsage(AttributeTargets.All, Inherited := False, AllowMultiple := True)>
Public Class SomeClass
Inherits Attribute
'...
End Class
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
[AttributeUsage(AttributeTargets::All, Inherited = false, AllowMultiple = true)]
O System.AttributeUsageAttribute tem três membros que são importantes para a criação de atributos personalizados: AttributeTargets, herdados, e AllowMultiple.
Membro da AttributeTargets
No exemplo anterior, AttributeTargets.All é especificada, indicando que este atributo pode ser aplicado a todos os elementos de programa. Como alternativa, você pode especificar AttributeTargets.Class , indicando que o atributo pode ser aplicado somente a uma classe, ou AttributeTargets.Method , indicando que o atributo pode ser aplicado somente a um método. Todos os elementos do programa podem ser marcados para descrição por um atributo personalizado dessa forma.
Você também pode passar várias instâncias de AttributeTargets. O fragmento de código a seguir especifica que um atributo personalizado pode ser aplicado a qualquer classe ou método.
<AttributeUsage(AttributeTargets.Class Or AttributeTargets.Method)>
Public Class SomeOtherClass
Inherits Attribute
'...
End Class
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
[AttributeUsage(AttributeTargets::Class | AttributeTargets::Method)]
Propriedade herdada
O Inherited propriedade indica se o atributo pode ser herdado pelas classes derivadas de classes para o qual o atributo é aplicado. Essa propriedade tem tanto um true (padrão) ou false sinalizador. Por exemplo, no exemplo de código a seguir, MyAttribute possui um valor padrão Inherited de true , enquanto YourAttribute tem um valor Inherited de false.
' This defaults to Inherited = true.
Public Class MyAttribute
Inherits Attribute
'...
End Class
<AttributeUsage(AttributeTargets.Method, Inherited := False)>
Public Class YourAttribute
Inherits Attribute
'...
End Class
// This defaults to Inherited = true.
public class MyAttribute : Attribute
{
//...
}
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class YourAttribute : Attribute
{
//...
}
// This defaults to Inherited = true.
public ref class MyAttribute : Attribute
{
//...
};
[AttributeUsage(AttributeTargets::Method, Inherited = false)]
public ref class YourAttribute : Attribute
{
//...
};
Os dois atributos são então aplicados a um método na classe base MyClass.
Public Class MeClass
<MyAttribute>
<YourAttribute>
Public Overridable Sub MyMethod()
'...
End Sub
End Class
public class MyClass
{
[MyAttribute]
[YourAttribute]
public virtual void MyMethod()
{
//...
}
}
public ref class MyClass
{
public:
[MyAttribute]
[YourAttribute]
virtual void MyMethod()
{
//...
}
};
Finalmene, a classe YourClass é herdada da classe base MyClass. O método MyMethod mostra MyAttribute, mas não YourAttribute.
Public Class YourClass
Inherits MeClass
' MyMethod will have MyAttribute but not YourAttribute.
Public Overrides Sub MyMethod()
'...
End Sub
End Class
public class YourClass : MyClass
{
// MyMethod will have MyAttribute but not YourAttribute.
public override void MyMethod()
{
//...
}
}
public ref class YourClass : MyClass
{
public:
// MyMethod will have MyAttribute but not YourAttribute.
virtual void MyMethod() override
{
//...
}
};
Propriedade AllowMultiple
A propriedade AllowMultiple indica se várias instâncias do seu atributo podem existir em um elemento. Se definido como true , várias instâncias são permitidas; se definido como False (o padrão), somente uma instância é permitida.
No exemplo de código a seguir, MyAttribute possui um valor padrão AllowMultiple de FALSE , enquanto YourAttribute tem um valor true .
' This defaults to AllowMultiple = false.
Public Class MyAttribute
Inherits Attribute
End Class
<AttributeUsage(AttributeTargets.Method, AllowMultiple := true)>
Public Class YourAttribute
Inherits Attribute
End Class
//This defaults to AllowMultiple = false.
public class MyAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class YourAttribute : Attribute
{
}
//This defaults to AllowMultiple = false.
public ref class MyAttribute : Attribute
{
};
[AttributeUsage(AttributeTargets::Method, AllowMultiple = true)]
public ref class YourAttribute : Attribute
{
};
Quando várias instâncias desses atributos são aplicadas, MyAttribute produz um erro do compilador. O exemplo de código a seguir mostra o uso válido de YourAttribute e o uso inválido de MyAttribute.
Public Class MyClass
' This produces an error.
' Duplicates are not allowed.
<MyAttribute>
<MyAttribute>
Public Sub MyMethod()
'...
End Sub
' This is valid.
<YourAttribute>
<YourAttribute>
Public Sub YourMethod()
'...
End Sub
End Class
public class MyClass
{
// This produces an error.
// Duplicates are not allowed.
[MyAttribute]
[MyAttribute]
public void MyMethod()
{
//...
}
// This is valid.
[YourAttribute]
[YourAttribute]
public void YourMethod()
{
//...
}
}
public ref class MyClass
{
public:
// This produces an error.
// Duplicates are not allowed.
[MyAttribute]
[MyAttribute]
void MyMethod()
{
//...
}
// This is valid.
[YourAttribute]
[YourAttribute]
void YourMethod()
{
//...
}
};
Se ambos os o AllowMultiple propriedade e o Inherited propriedade estiver definida como true, uma classe que é herdada de outra classe pode herdar um atributo e ter outra instância do mesmo atributo aplicado na mesma classe filho. Se AllowMultiple estiver definida como False , os valores de quaisquer atributos na classe pai serão substituídos por novas instâncias do mesmo atributo na classe filha.
Declarar a classe de atributos
Depois de aplicar a AttributeUsageAttribute, você pode começar a definir as especificidades do seu atributo. A declaração de uma classe de atributos parece com a declaração de uma classe tradicional, como demonstrado pelo código a seguir.
<AttributeUsage(AttributeTargets.Method)>
Public Class MyAttribute
Inherits Attribute
' . . .
End Class
[AttributeUsage(AttributeTargets.Method)]
public class MyAttribute : Attribute
{
// . . .
}
[AttributeUsage(AttributeTargets::Method)]
public ref class MyAttribute : Attribute
{
// . . .
};
Esta definição de atributo demonstra os seguintes pontos:
Classes de atributo devem ser declaradas como classes públicas.
Por convenção, o nome da classe de atributos termina com a palavra Attribute. Enquanto não for necessária, esta convenção é recomendada para facilitar a leitura. Quando o atributo é aplicado, a inclusão de atributo de palavra é opcional.
Todas as classes de atributo devem herdar direta ou indiretamente de System.Attribute .
No Microsoft Visual Basic, todas as classes de atributos personalizados devem ter o atributo AttributeUsageAttribute.
Declarar os construtores
Os atributos são inicializados com construtores da mesma forma como as classes tradicionais. O fragmento de código a seguir ilustra um típico construtor de atributos. Esse construtor público aceita um parâmetro e define seu valor igual a uma variável do membro.
Public Sub New(myvalue As Boolean)
Me.myvalue = myvalue
End Sub
public MyAttribute(bool myvalue)
{
this.myvalue = myvalue;
}
MyAttribute(bool myvalue)
{
this->myvalue = myvalue;
}
Você pode sobrecarregar o construtor para acomodar diferentes combinações de valores. Se você também definir uma propriedade para sua classe de atributos personalizados, você pode usar uma combinação de parâmetros nomeados e posicionais ao inicializar o atributo. Normalmente, você define todos os parâmetros necessários como posicionais e todos os parâmetros opcionais como nomeados. Nesse caso, o atributo não pode ser inicializado sem o parâmetro necessário. Todos os outros parâmetros são opcionais. Observe que em Visual Basic, construtores para uma classe de atributos não devem usar um argumento ParamArray.
O exemplo de código a seguir mostra como um atributo que usa que o construtor anterior pode ser aplicado usando parâmetros necessários e opcionais. Ele pressupõe que o atributo tem um valor booleano necessário e uma de sequência de caracteres opcional.
' One required (positional) and one optional (named) parameter are applied.
<MyAttribute(false, OptionalParameter := "optional data")>
Public Class SomeClass
'...
End Class
' One required (positional) parameter is applied.
<MyAttribute(false)>
Public Class SomeOtherClass
'...
End Class
// One required (positional) and one optional (named) parameter are applied.
[MyAttribute(false, OptionalParameter = "optional data")]
public class SomeClass
{
//...
}
// One required (positional) parameter is applied.
[MyAttribute(false)]
public class SomeOtherClass
{
//...
}
// One required (positional) and one optional (named) parameter are applied.
[MyAttribute(false, OptionalParameter = "optional data")]
public ref class SomeClass
{
//...
};
// One required (positional) parameter is applied.
[MyAttribute(false)]
public ref class SomeOtherClass
{
//...
};
Declarando propriedades
Se você desejar definir um parâmetro nomeado ou fornecer uma maneira fácil de retornar os valores armazenados pelo seu atributo, declare uma propriedade. Propriedades de atributo devem ser declaradas como entidades públicas com uma descrição do tipo de dados que será retornado. Definir a variável que irá conter o valor de sua propriedade e associá-lo com o obter e set métodos. O exemplo de código a seguir demonstra como implementar uma propriedade simples em seu atributo.
Public Property MyProperty As Boolean
Get
Return Me.myvalue
End Get
Set
Me.myvalue = Value
End Set
End Property
public bool MyProperty
{
get {return this.myvalue;}
set {this.myvalue = value;}
}
property bool MyProperty
{
bool get() {return this->myvalue;}
void set(bool value) {this->myvalue = value;}
}
Exemplo de atributo personalizado
Esta seção incorpora as informações anteriores e mostra como criar um atributo simples que documenta informações sobre o autor de uma seção do código. O atributo neste exemplo armazena o nome e o nível do programador, e se o código tenha sido revisado. Ele usa três variáveis privadas para armazenar os valores reais para salvar. Cada variável é representado por uma propriedade pública que obtém e define os valores. Finalmente, o construtor é definido com dois parâmetros necessários.
<AttributeUsage(AttributeTargets.All)>
Public Class DeveloperAttribute
Inherits Attribute
' Private fields.
Private myname As String
Private mylevel As String
Private myreviewed As Boolean
' This constructor defines two required parameters: name and level.
Public Sub New(name As String, level As String)
Me.myname = name
Me.mylevel = level
Me.myreviewed = False
End Sub
' Define Name property.
' This is a read-only attribute.
Public Overridable ReadOnly Property Name() As String
Get
Return myname
End Get
End Property
' Define Level property.
' This is a read-only attribute.
Public Overridable ReadOnly Property Level() As String
Get
Return mylevel
End Get
End Property
' Define Reviewed property.
' This is a read/write attribute.
Public Overridable Property Reviewed() As Boolean
Get
Return myreviewed
End Get
Set
myreviewed = value
End Set
End Property
End Class
[AttributeUsage(AttributeTargets.All)]
public class DeveloperAttribute : 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 ref class DeveloperAttribute : Attribute
{
// Private fields.
private:
String^ name;
String^ level;
bool reviewed;
public:
// This constructor defines two required parameters: name and level.
DeveloperAttribute(String^ name, String^ level)
{
this->name = name;
this->level = level;
this->reviewed = false;
}
// Define Name property.
// This is a read-only attribute.
virtual property String^ Name
{
String^ get() {return name;}
}
// Define Level property.
// This is a read-only attribute.
virtual property String^ Level
{
String^ get() {return level;}
}
// Define Reviewed property.
// This is a read/write attribute.
virtual property bool Reviewed
{
bool get() {return reviewed;}
void set(bool value) {reviewed = value;}
}
};
Você pode aplicar este atributo usando o nome completo, DeveloperAttribute, ou o nome abreviado, Developer, em uma das seguintes maneiras.
<Developer("Joan Smith", "1")>
-or-
<Developer("Joan Smith", "1", Reviewed := true)>
[Developer("Joan Smith", "1")]
-or-
[Developer("Joan Smith", "1", Reviewed = true)]
[Developer("Joan Smith", "1")]
-or-
[Developer("Joan Smith", "1", Reviewed = true)]
O primeiro exemplo mostra o atributo aplicado apenas com os parâmetros nomeados ncessários, enquanto o segundo exemplo mostra o atributo aplicado com ambos os parâmetros necessários e opcionais.