Condividi tramite


Scrittura di attributi personalizzati

Aggiornamento: novembre 2007

Per progettare attributi personalizzati non è necessario apprendere numerosi nuovi concetti. Se si ha dimestichezza con la programmazione orientata ad oggetti e si è in grado di progettare classi si dispone già di gran parte delle conoscenze necessarie. Gli attributi personalizzati sono essenzialmente classi tradizionali derivate direttamente o indirettamente da System.Attribute. Analogamente alle classi tradizionali, gli attributi personalizzati contengono metodi per la memorizzazione e il recupero di dati.

Di seguito sono illustrati i passaggi iniziali di una corretta progettazione di classi di attributi personalizzati:

  • Applicazione di AttributeUsageAttribute

  • Dichiarazione della classe di un attributo

  • Dichiarazione dei costruttori

  • Dichiarazione delle proprietà

In questa sezione verrà descritto ciascuno di questi passaggi e verrà infine illustrato un esempio di attributo personalizzato.

Applicazione di AttributeUsageAttribute

La dichiarazione di un attributo personalizzato ha inizio con l'attributo 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 precisare gli elementi su cui l'attributo è applicabile. Nel frammento di codice riportato di seguito si illustra come utilizzare l'attributo AttributeUsageAttribute.

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

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

Membro AttributeTargets

Nell'esempio precedente è specificato AttributeTargets.All, per indicare che questo attributo è applicabile a tutti gli elementi di programma. In alternativa è possibile specificare AttributeTargets.Class oppure AttributeTargets.Method, a indicare che l'attributo può essere applicato rispettivamente solo a una classe o solo a un metodo. Tutti gli elementi di programma possono essere contrassegnati per essere descrivibili attraverso un attributo personalizzato.

È inoltre possibile passare più istanze di AttributeTargets. Nel frammento di codice riportato di seguito viene specificato che un attributo personalizzato può essere applicato a qualsiasi tipo o metodo.

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

Proprietà Inherited

La proprietà Inherited indica se l'attributo può essere ereditato da classi derivate dalle classi su cui l'attributo è applicato. Questa proprietà ammette i flag true e false. Il primo rappresenta il valore predefinito. Nell'esempio di codice riportato di seguito MyAttribute assume per Inherited il valore predefinito true, mentre YourAttribute assume per Inherited il valore 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

I due attributi vengono quindi applicati a un metodo della classe base 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

La classe YourClass viene infine ereditata dalla classe base MyClass. Il metodo MyMethod presenta MyAttribute, ma non 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

Proprietà AllowMultiple

La proprietà AllowMultiple indica se su un elemento possono esistere più istanze dell'attributo. Se è impostata su true saranno consentite più istanze, mentre se è impostata sul valore predefinito false potrà esistere un'unica istanza.

Nell'esempio di codice riportato di seguito MyAttribute assume per AllowMultiple il valore predefinito false, mentre YourAttribute assume il valore 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

Quando vengono applicate più istanze di questi attributi, viene generato un errore di compilazione per MyAttribute. Nell'esempio di codice riportato di seguito si illustra il corretto utilizzo di YourAttribute e l'utilizzo errato 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(){
    //...
    }
}
' 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

Se sia la proprietà AllowMultiple che la proprietà Inherited sono impostate su true una classe ereditata da un'altra classe potrà ereditare un attributo e nella stessa classe figlio potrà essere applicata una seconda istanza dello stesso attributo. Se AllowMultiple è impostata su false i valori di eventuali attributi della classe padre verranno sostituiti da quelli delle nuove istanze dello stesso attributo nella classe figlio.

Dichiarazione della classe di un attributo

Una volta applicato l'attributo AttributeUsageAttribute, è possibile iniziare a definire le specifiche dell'attributo stesso. La dichiarazione di una classe di attributi è analoga alla dichiarazione di una classe tradizionale, come illustrato nel seguente codice:

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

Questa definizione di attributo dimostra i seguenti punti:

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

  • Per convenzione, il nome della classe di attributo termina con la parola Attribute. Benché non sia obbligatorio, il rispetto di tale convenzione migliora la leggibilità del codice. Quando si applica l'attributo, 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 presentare l'attributo AttributeUsageAttribute.

Dichiarazione dei costruttori

Gli attributi vengono inizializzati con i costruttori con modalità analoghe a quelle delle classi tradizionali. Nel frammento di codice riportato di seguito viene illustrato un tipico costruttore di attributi. Questo costruttore pubblico riceve un parametro e ne assegna il valore a una variabile membro.

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

È possibile sovraccaricare il costruttore per inserire diverse combinazioni di valori. Se si definisce anche una proprietà per la classe di attributi personalizzati sarà possibile utilizzare una combinazione di parametri predefiniti e posizionali all'inizializzazione dell'attributo. Tutti i parametri obbligatori vengono in genere definiti come parametri posizionali e tutti i parametri facoltativi come parametri predefiniti. In questo caso non è possibile inizializzare l'attributo senza il parametro obbligatorio. Tutti gli altri parametri sono facoltativi. In Visual Basic l'argomento ParamArray non deve essere utilizzato con i costruttori di una classe di attributi.

Nell'esempio di codice riportato di seguito si illustra come applicare un attributo che si avvale del costruttore precedente mediante parametri facoltativi e obbligatori. Nell'esempio si presuppone che l'attributo presenti un valore Boolean obbligatorio e una proprietà della stringa facoltativa.

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

Dichiarazione delle proprietà

Se si desidera definire un parametro predefinito o fornire un metodo semplice per la restituzione dei valori memorizzati dall'attributo dichiarare una proprietà. Le proprietà di un 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. Nell'esempio di codice che segue si illustra come implementare una proprietà semplice 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, basata sulle informazioni descritte in precedenza, si illustra come progettare un attributo semplice che offra informazioni sull'autore di una sezione del codice. Nell'attributo di questo esempio è memorizzato il nome e il livello del programmatore ed è specificato se il codice è stato rivisto. Per la memorizzazione dei valori effettivi da salvare vengono utilizzate tre variabili private. Ciascuna variabile è rappresentata da una proprietà pubblica che consente di visualizzare e impostare i valori. Il costruttore viene infine definito con due parametri obbligatori.

[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

È possibile applicare questo attributo utilizzandone il nome completo, DeveloperAttribute, oppure il nome abbreviato, Developer, in uno dei modi descritti di seguito.

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

Nel primo esempio è mostrata l'applicazione dell'attributo con i soli parametri predefiniti obbligatori, mentre nel secondo esempio è illustrata l'applicazione dell'attributo sia con i parametri obbligatori che con quelli facoltativi.

Vedere anche

Riferimenti

System.Attribute

AttributeUsageAttribute

Altre risorse

Estensione di metadati mediante attributi