Condividi tramite


Scrivere attributi personalizzati

Per progettare attributi personalizzati, non è necessario apprendere molti nuovi concetti. Se si ha familiarità con la programmazione orientata agli oggetti e si sa come progettare le classi, si dispone già della maggior parte delle conoscenze necessarie. Gli attributi personalizzati sono classi tradizionali che derivano direttamente o indirettamente dalla System.Attribute classe . Analogamente alle classi tradizionali, gli attributi personalizzati contengono metodi che archiviano e recuperano i dati.

I passaggi principali per progettare correttamente le classi di attributi personalizzati sono i seguenti:

Questa sezione descrive ognuno di questi passaggi e termina con un esempio di attributo personalizzato.

Uso dell'attributo AttributeUsageAttribute

Una dichiarazione di attributo personalizzata inizia con l'attributo System.AttributeUsageAttribute , che definisce alcune delle caratteristiche chiave della classe dell'attributo. Ad esempio, è possibile specificare se l'attributo può essere ereditato da altre classi o a quali elementi può essere applicato l'attributo. Il frammento di codice seguente illustra come usare :AttributeUsageAttribute

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

Include AttributeUsageAttribute tre membri importanti per la creazione di attributi personalizzati: AttributeTargets, Inherited e AllowMultiple.

Membro AttributeTargets

Nell'esempio precedente viene AttributeTargets.All specificato , a indicare che questo attributo può essere applicato a tutti gli elementi del programma. In alternativa, è possibile specificare AttributeTargets.Class, che indica che l'attributo può essere applicato solo a una classe o AttributeTargets.Method, a indicare che l'attributo può essere applicato solo a un metodo. Tutti gli elementi del programma possono essere contrassegnati per la descrizione da un attributo personalizzato in questo modo.

È anche possibile passare più AttributeTargets valori. Il frammento di codice seguente specifica che un attributo personalizzato può essere applicato a qualsiasi classe o metodo:

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

Proprietà ereditata

La AttributeUsageAttribute.Inherited proprietà indica se l'attributo può essere ereditato da classi derivate dalle classi a cui viene applicato l'attributo. Questa proprietà accetta un true flag (impostazione predefinita) o false . Nell'esempio seguente, MyAttribute ha un valore predefinito Inherited di true, mentre YourAttribute ha un valore Inherited di 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

I due attributi vengono quindi applicati a un metodo nella classe MyClassbase :

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

Infine, la classe YourClass viene ereditata dalla classe MyClassbase . Il metodo MyMethod mostra MyAttribute ma non 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, proprietà

La AttributeUsageAttribute.AllowMultiple proprietà indica se in un elemento possono esistere più istanze dell'attributo. Se impostato su true, sono consentite più istanze. Se impostato su false (impostazione predefinita), è consentita una sola istanza.

Nell'esempio seguente, MyAttribute ha un valore predefinito di AllowMultiple, mentre false ha un valore di YourAttribute.

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

Quando vengono applicate più istanze di questi attributi, MyAttribute genera un errore del compilatore. Nell'esempio di codice seguente viene illustrato l'uso valido di YourAttribute e l'uso non valido di 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

Se sia la AllowMultiple proprietà che la Inherited proprietà sono impostate su true, una classe ereditata da un'altra classe può ereditare un attributo e avere un'altra istanza dello stesso attributo applicato nella stessa classe figlio. Se AllowMultiple è impostato su false, i valori di qualsiasi attributo nella classe padre verranno sovrascritti dalle nuove istanze dello stesso attributo nella classe figlio.

Dichiarazione della classe attributo

Dopo aver applicato il AttributeUsageAttribute, inizia a definire le specifiche del tuo attributo. La dichiarazione di una classe di attributi è simile alla dichiarazione di una classe tradizionale, come illustrato nel codice seguente:

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

Questa definizione di attributo illustra i punti seguenti:

  • Le classi di attributi devono essere dichiarate come classi pubbliche.

  • Per convenzione, il nome della classe di attributi termina con la parola Attribute. Sebbene non sia necessario, questa convenzione è consigliata per la leggibilità. Quando viene applicato l'attributo, l'inclusione della parola Attribute è facoltativa.

  • Tutte le classi di attributi devono ereditare direttamente o indirettamente dalla System.Attribute classe .

  • In Microsoft Visual Basic tutte le classi di attributi personalizzati devono avere l'attributo System.AttributeUsageAttribute .

Dichiarazione dei costruttori

Proprio come le classi tradizionali, gli attributi vengono inizializzati con i costruttori. Il frammento di codice seguente illustra un tipico costruttore di attributi. Questo costruttore pubblico accetta un parametro e imposta una variabile membro uguale al relativo valore.

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

È possibile sovraccaricare il costruttore per gestire diverse combinazioni di valori. Se si definisce anche una proprietà per la classe di attributi personalizzata, è possibile usare una combinazione di parametri denominati e posizionali durante l'inizializzazione dell'attributo. In genere, tutti i parametri obbligatori vengono definiti come posizionali e tutti i parametri facoltativi come denominati. In questo caso, l'attributo non può essere inizializzato senza il parametro obbligatorio. Tutti gli altri parametri sono facoltativi.

Annotazioni

In Visual Basic, i costruttori per una classe attributo non dovrebbero usare un argomento ParamArray.

Nell'esempio di codice seguente viene illustrato come applicare un attributo che usa il costruttore precedente usando parametri facoltativi e obbligatori. Si presuppone che l'attributo abbia un valore booleano obbligatorio e una proprietà stringa facoltativa.

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

Dichiarazione delle proprietà

Se si vuole definire un parametro denominato o fornire un modo semplice per restituire i valori archiviati dall'attributo, dichiarare una proprietà. Le proprietà degli attributi devono essere dichiarate come entità pubbliche con una descrizione del tipo di dati che verrà restituito. Definire la variabile che conterrà il valore della proprietà e associarla ai metodi get e set. Nell'esempio di codice seguente viene illustrato come implementare una proprietà nell'attributo :

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

Esempio di attributo personalizzato

In questa sezione vengono incorporate le informazioni precedenti e viene illustrato come progettare un attributo che documenta le informazioni sull'autore di una sezione di codice. L'attributo in questo esempio archivia il nome e il livello del programmatore e indica se il codice è stato esaminato. Usa tre variabili private per archiviare i valori effettivi da salvare. Ogni variabile è rappresentata da una proprietà pubblica che ottiene e imposta i valori. Infine, il costruttore viene definito con due parametri obbligatori:

[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

È possibile applicare questo attributo usando il nome completo, DeveloperAttributeo usando il nome abbreviato, Developer, in uno dei modi seguenti:

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

-or-

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

-or-

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

Il primo esempio mostra l'attributo applicato solo con i parametri denominati obbligatori. Il secondo esempio mostra l'attributo applicato con i parametri obbligatori e facoltativi.

Vedere anche