Per visualizzare l'articolo in inglese, selezionare la casella di controllo Inglese. È possibile anche visualizzare il testo inglese in una finestra popup posizionando il puntatore del mouse sopra il testo.
Traduzione
Inglese

Scrittura di attributi personalizzati

 

Per progettare attributi personalizzati, non è necessario apprendere molti nuovi concetti. Se si ha familiarità con la programmazione orientata agli oggetti e si è in grado di progettare le classi, si ha già gran parte delle conoscenze necessarie. Gli attributi personalizzati sono essenzialmente classi tradizionali che derivano direttamente o indirettamente da System.Attribute. Analogamente alle classi tradizionali, gli attributi personalizzati contengono metodi che archiviano e recuperano dati.

I passaggi fondamentali per progettare classi di attributi personalizzati sono i seguenti:

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

La dichiarazione di attributo personalizzato inizia con AttributeUsageAttribute, che definisce alcune delle caratteristiche chiave della classe di attributi. Ad esempio, è possibile specificare se l'attributo può essere ereditato da altre classi o gli elementi a cui può essere applicato l'attributo. Il frammento di codice seguente illustra come specificare AttributeUsageAttribute.

[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]

L'oggetto System.AttributeUsageAttribute ha tre membri importanti per la creazione di attributi personalizzati: AttributeTargets, Inherited e AllowMultiple.

Nell'esempio precedente è specificato AttributeTargets, a indicare che questo attributo può essere applicato a tutti gli elementi di programma. In alternativa, è possibile specificare AttributeTargets.Class, a indicare che l'attributo può essere applicato solo a una classe, oppure AttributeTargets.Method, a indicare che l'attributo può essere applicato solo a un metodo. Questa procedura può essere usata per contrassegnare tutti gli elementi di programma per la descrizione mediante un attributo personalizzato.

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

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]

La proprietà AttributeUsageAttribute.Inherited indica se l'attributo può essere ereditato da classi derivate dalle classi a cui è applicato l'attributo. Questa proprietà accetta un flag true (valore predefinito) o false. Nell'esempio seguente, ad esempio, MyAttribute ha una proprietà Inherited con il valore predefinito true, mentre YourAttribute ha una proprietà Inherited con valore false.

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

[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class YourAttribute : Attribute
{
    //...
}

I due attributi vengono quindi applicati a un metodo nella classe base MyClass.

public class MyClass
{
    [MyAttribute]
    [YourAttribute]
    public virtual void MyMethod()
    {
        //...
    }
}

Infine, la classe YourClass viene ereditata dalla classe base MyClass. Il metodo MyMethod mostra MyAttribute, ma non YourAttribute.

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

}

La proprietà AttributeUsageAttribute.AllowMultiple indica se in un elemento possono esistere istanze multiple dell'attributo. Se è impostata su true, sono consentite istanze multiple. Se invece è impostata su false (valore predefinito), è consentita solo un'istanza.

Nell'esempio seguente MyAttribute ha una proprietà AllowMultiple con il valore predefinito false, mentre il valore di YourAttribute è true.

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

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class YourAttribute : Attribute
{
}

Quando vengono applicate istanze multiple di questi attributi, MyAttribute genera un errore del compilatore. L'esempio di codice seguente mostra 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()
    {
        //...
    }
}

Se le proprietà AllowMultiple e Inherited sono entrambe impostate su true, una classe ereditata da un'altra classe può ereditare un attributo e determinare l'applicazione di un'altra istanza dello stesso attributo nella stessa classe figlio. Se la proprietà AllowMultiple è impostata su false, i valori degli attributi nella classe padre verranno sovrascritti dalle nuove istanze dello stesso attributo nella classe figlio.

Dopo avere applicato AttributeUsageAttribute, è possibile iniziare a definire le specifiche dell'attributo. La dichiarazione di una classe di attributi è simile alla dichiarazione di una classe tradizionale, come dimostrato dal codice seguente.

[AttributeUsage(AttributeTargets.Method)]
public class MyAttribute : Attribute
{
    // . . .
}

Questa definizione di attributo dimostra quanto segue:

  • 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 obbligatorio, questa convenzione è consigliabile per migliorare la leggibilità. Quando l'attributo è applicato, l'inclusione della parola Attribute è facoltativa.

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

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

Gli attributi, così come le classi tradizionali, vengono inizializzati con costruttori. Il frammento di codice seguente illustra un tipico costruttore di attributi. Questo costruttore pubblico accetta un parametro e ne imposta il valore uguale a una variabile membro.

public MyAttribute(bool myvalue)
{
    this.myvalue = myvalue;
}

È possibile eseguire l'overload del costruttore per supportare diverse combinazioni di valori. Se si definisce anche una proprietà per la classe di attributi personalizzati, è possibile usare una combinazione di parametri denominati e posizionali quando si inizializza l'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. Si noti che, in Visual Basic, i costruttori di una classe Attribute non devono usare un argomento ParamArray.

L'esempio di codice seguente illustra come applicare un attributo che usa il costruttore precedente mediante i parametri obbligatori e facoltativi. 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
{
    //...
}

Se si vuole definire un parametro denominato o fornire un modo semplice per restituire i valori archiviati dall'attributo, dichiarare una proprietà. Le proprietà dell'attributo 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. L'esempio di codice seguente illustra come implementare una semplice proprietà nell'attributo.

public bool MyProperty
{
    get {return this.myvalue;}
    set {this.myvalue = value;}
}

Questa sezione include le informazioni precedenti e illustra come progettare un semplice 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 specifica se il codice è stato rivisto. 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 è 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;}
    }
}

Questo attributo può essere applicato usando il nome completo DeveloperAttribute oppure il nome abbreviato Developer in uno dei modi seguenti.

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

-or-

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

Il primo esempio mostra l'attributo applicato solo con i parametri denominati obbligatori, mentre il secondo esempio mostra l'attributo applicato con i parametri sia obbligatori che facoltativi.

Mostra: