Compartir a través de


Escritura de atributos personalizados

Para diseñar atributos personalizados, no es necesario aprender muchos conceptos nuevos. Si está familiarizado con la programación orientada a objetos y sabe cómo diseñar clases, ya tiene la mayoría de los conocimientos necesarios. Los atributos personalizados son clases tradicionales que derivan directa o indirectamente de la System.Attribute clase . Al igual que las clases tradicionales, los atributos personalizados contienen métodos que almacenan y recuperan datos.

Los pasos principales para diseñar correctamente clases de atributos personalizados son los siguientes:

En esta sección se describe cada uno de estos pasos y se concluye con un ejemplo de atributo personalizado.

Aplicación de "AttributeUsageAttribute"

Una declaración de atributo personalizado comienza con el System.AttributeUsageAttribute atributo , que define algunas de las características clave de la clase de atributo. Por ejemplo, puede especificar si el atributo se puede heredar por otras clases o a qué elementos se puede aplicar el atributo. En el fragmento de código siguiente se muestra cómo usar :AttributeUsageAttribute

[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
<AttributeUsage(AttributeTargets.All, Inherited:=False, AllowMultiple:=True)>
Public Class SomeClass
    Inherits Attribute
    '...
End Class

AttributeUsageAttribute tiene tres miembros importantes para la creación de atributos personalizados: AttributeTargets, Inherited y AllowMultiple.

AttributeTargets (miembro)

En el ejemplo anterior, AttributeTargets.All se especifica , que indica que este atributo se puede aplicar a todos los elementos del programa. Como alternativa, puede especificar AttributeTargets.Class, que indica que el atributo solo se puede aplicar a una clase o AttributeTargets.Method, lo que indica que el atributo solo se puede aplicar a un método . Todos los elementos del programa se pueden marcar para su descripción mediante un atributo personalizado de esta manera.

También puede pasar varios AttributeTargets valores. El fragmento de código siguiente especifica que se puede aplicar un atributo personalizado a cualquier clase o método:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
<AttributeUsage(AttributeTargets.Class Or AttributeTargets.Method)>
Public Class SomeOtherClass
    Inherits Attribute
    '...
End Class

Propiedad heredada

La AttributeUsageAttribute.Inherited propiedad indica si el atributo se puede heredar por clases derivadas de las clases a las que se aplica el atributo. Esta propiedad acepta una marca true (por defecto) o una marca false. En el ejemplo siguiente, MyAttribute tiene un valor predeterminado Inherited de true, mientras YourAttribute que tiene un Inherited valor de false:

// This defaults to Inherited = true.
public class MyAttribute : Attribute
{
    //...
}

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

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

A continuación, los dos atributos se aplican a un método de la clase MyClassbase :

public class MyClass
{
    [MyAttribute]
    [YourAttribute]
    public virtual void MyMethod()
    {
        //...
    }
}
Public Class MeClass
    <MyAttribute>
    <YourAttribute>
    Public Overridable Sub MyMethod()
        '...
    End Sub
End Class

Por último, la clase YourClass se hereda de la clase MyClassbase . El método MyMethod muestra MyAttribute pero no YourAttribute:

public class YourClass : MyClass
{
    // MyMethod will have MyAttribute but not YourAttribute.
    public override void MyMethod()
    {
        //...
    }
}
Public Class YourClass
    Inherits MeClass
    ' MyMethod will have MyAttribute but not YourAttribute.
    Public Overrides Sub MyMethod()
        '...
    End Sub

End Class

AllowMultiple (propiedad)

La AttributeUsageAttribute.AllowMultiple propiedad indica si pueden existir varias instancias del atributo en un elemento . Si se establece en true, se permiten varias instancias. Si se establece en false (valor predeterminado), solo se permite una instancia.

En el ejemplo siguiente, MyAttribute tiene un valor predeterminado AllowMultiple de false, mientras YourAttribute que tiene un valor de true:

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

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

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

Cuando se aplican varias instancias de estos atributos, MyAttribute se produce un error del compilador. En el ejemplo de código siguiente se muestra el uso válido de YourAttribute y el uso no válido de 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()
    {
        //...
    }
}
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

Si tanto la AllowMultiple propiedad como la Inherited propiedad se establecen al true, una clase que se hereda de otra clase puede heredar un atributo y tener otra vez el mismo atributo aplicado en la misma clase hija. Si AllowMultiple se establece en false, los valores de los atributos de la clase padre se sobrescribirán por nuevas instancias del mismo atributo en la clase hija.

Declaración de la clase de atributo

Después de aplicar el AttributeUsageAttribute, empiece a definir los detalles de su atributo. La declaración de una clase de atributo es similar a la declaración de una clase tradicional, como se muestra en el código siguiente:

[AttributeUsage(AttributeTargets.Method)]
public class MyAttribute : Attribute
{
    // . . .
}
<AttributeUsage(AttributeTargets.Method)>
Public Class MyAttribute
    Inherits Attribute
    ' . . .
End Class

Esta definición de atributo muestra los siguientes puntos:

  • Las clases de atributo deben declararse como clases públicas.

  • Por convención, el nombre de la clase de atributo termina con la palabra Attribute. Aunque no es necesario, esta convención se recomienda para mejorar la legibilidad. Cuando se aplica el atributo, la inclusión de la palabra Attribute es opcional.

  • Todas las clases de atributo deben heredar directa o indirectamente de la System.Attribute clase .

  • En Microsoft Visual Basic, todas las clases de atributos personalizados deben tener el System.AttributeUsageAttribute atributo .

Declarar constructores

Al igual que las clases tradicionales, los atributos se inicializan con constructores. En el fragmento de código siguiente se muestra un constructor de atributos típico. Este constructor público toma un parámetro y establece una variable miembro igual a su valor.

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

Puede sobrecargar el constructor para dar cabida a diferentes combinaciones de valores. Si también define una propiedad para la clase de atributo personalizada, puede usar una combinación de parámetros con nombre y posicional al inicializar el atributo. Normalmente, se definen todos los parámetros necesarios como posicionales y todos los parámetros opcionales como denominados. En este caso, el atributo no se puede inicializar sin el parámetro necesario. Todos los demás parámetros son opcionales.

Nota:

En Visual Basic, los constructores de una clase de atributo no deben usar un ParamArray argumento .

En el ejemplo de código siguiente se muestra cómo se puede aplicar un atributo que usa el constructor anterior mediante parámetros opcionales y obligatorios. Se supone que el atributo tiene un valor booleano necesario y una propiedad de cadena opcional.

// 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 Class SomeClass
    '...
End Class

' One required (positional) parameter is applied.
<MyAttribute(false)>
Public Class SomeOtherClass
    '...
End Class

Declarar propiedades

Si desea definir un parámetro con nombre o proporcionar una manera sencilla de devolver los valores almacenados por el atributo, declare una propiedad. Las propiedades de atributo deben declararse como entidades públicas con una descripción del tipo de datos que se devolverá. Defina la variable que contendrá el valor de su propiedad y asígnela a los métodos get y set. En el ejemplo de código siguiente se muestra cómo implementar una propiedad en el atributo :

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

Ejemplo de atributo personalizado

En esta sección se incorpora la información anterior y se muestra cómo diseñar un atributo que documente información sobre el autor de una sección de código. El atributo de este ejemplo almacena el nombre y el nivel del programador y si se ha revisado el código. Usa tres variables privadas para almacenar los valores reales que se van a guardar. Cada variable se representa mediante una propiedad pública que obtiene y establece los valores. Por último, el constructor se define con dos parámetros necesarios:

[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 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

Puede aplicar este atributo mediante el nombre completo, DeveloperAttribute, o mediante el nombre abreviado, Developer, de una de las maneras siguientes:

[Developer("Joan Smith", "1")]

-or-

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

-or-

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

En el primer ejemplo se muestra el atributo aplicado solo con los parámetros con nombre necesarios. En el segundo ejemplo se muestra el atributo aplicado con los parámetros obligatorios y opcionales.

Consulte también