A47. Gli Attributi
Gli attributi sono un'entità di programmazione non molto conosciuta dai giovani programmatori, ma altresì davvero utile. Essi servono
a definire quella parte di informazioni conosciuta sotto il nome di metadati: i metadati servono a specificare ulteriori dettagli
riguardo a un membro di classe e al suo comportamento. Gli attributi non sono direttive che forniscono comandi e perciò non influiscono
direttamente sul membro a cui sono applicati, ma sulla sua relazione con il resto dell'applicazione. C'è solo un modo per utilizzarli: la
Reflection. Infatti non esiste altra via per individuarli, anche dallo stesso codice nel quale vengono scritti. La sintassi con cui si
assegna un attributo è:
Tuttavia, all'occorrenza, ne userò qualcuno nei prossimi capitoli riguardo ad ambiti differenti, come i file XML, gli eventi, le proprietà dei controlli eccetera...
<[Attributo]([Parametri del costruttore])> _ [Membro]Ad esempio:
<Description("Descrizione del metodo")> _
Public Sub UnMetodo()
L'attributo Description (appartenente al namespace System.ComponentModel) serve solamente a specificare una piccola descrizione del membro
a cui è applicato, in questo caso un metodo, come se fosse una targhetta di riconoscimento. Attraverso questo procedimento, l'Object Browser
scritto nel capitolo precedente potrebbe rilevare anche le descrizioni dei membri, se presenti. Dato che gli attributi sono molto specifici
e servono in determinate situazioni che non si possono analizzare in questa sede, nel capitolo spiegherò come scrivere un nuovo attributo
e utilizzarlo per modificare il comportamento del programma.Tuttavia, all'occorrenza, ne userò qualcuno nei prossimi capitoli riguardo ad ambiti differenti, come i file XML, gli eventi, le proprietà dei controlli eccetera...
Scrivere attributi
Un attributo, a livello teorico, non è altro che una classe derivata da System.Attribute e il suo nome deve sempre terminare con la parola
"Attribute". Ecco un esempio:
L'output sarà, ad esempio:Module Module1 'Per convenzione gli attributi possono esporre solo proprietà 'Questa classe definisce il nome di una proprietà a run-time Class NameAttributeInherits AttributePrivate ReadOnly _NameAs String Public ReadOnly Property Name()As String Get Return _NameEnd Get End Property 'Il costruttore viene richiamato automaticamente quando 'l'attributo sta per essere applicato a un membro Sub New (ByVal NameAs String ) _Name = NameEnd Sub End Class 'Classe che rappresenta una canzone Class SongPrivate _Title, _AuthorAs String 'Quando il programma principale la leggerà, questa proprietà 'sarà visualizzata con il nome "Titolo" anzichè "Title" 'Si noti che è sufficiente la prima parte del nome dell'attributo, 'in questo caso Name anzichè NameAttribute <Name("Titolo")> _Public Property Title()As String Get Return _TitleEnd Get Set (ByVal ValueAs String ) _Title = ValueEnd Set End Property <Name("Autore")> _Public Property Author()As String Get Return _AuthorEnd Get Set (ByVal ValueAs String ) _Author = ValueEnd Set End Property End Class Sub Main()Dim SAs New Song 'Il Type associato a Song Dim SongTypeAs Type = GetType(Song) 'Il Type associato a NameAttribute, servirà in seguito Dim NameTypeAs Type = GetType(NameAttribute) 'In questo caso è necessario tutto il nome Dim AttrAs NameAttribute Console.WriteLine("Completare i campi per l'oggetto Song:") Console.WriteLine() 'Chiede all'utente di immettere tutti i campi disponibili 'in Song, rappresentati dalle sue proprietà For Each PIAs PropertyInfoIn SongType.GetProperties() 'Tenta di ottenere l'attributo associato alla proprietà. 'GetCustomAttribues è un metodo comune a tutti i tipi della 'Reflection che rappresentano membri di classe e restituisce 'un array di attributi di un dato tipo, opzionalmente 'cercando nella gerarchia di ereditarietà Attr = TryCast(PI.GetCustomAttributes(NameType, False)(0), _ NameAttribute) 'L'operatore TryCast restituisce Nothing se fallisce la 'conversione perciò se Attr = Nothing, non c'è alcun 'attributo Name applicato alla proprietà If AttrIs Nothing Then 'Continua il ciclo Continue For End If Dim ValueAs Object 'Altrimenti, visualizza il nome e chiede di 'immettere un valore Console.Write("{0}: ", Attr.Name) 'Legge il valore Value = Console.ReadLine 'E lo assegna alla relativa proprietà 'PropertyInfo e FieldInfo hanno due metodi opposti: 'GetValue e SetValue '- GetValue(O, I()) : O è l'oggetto in cui impostare la 'proprietà o il campo, mentre I è un array di oggetti che 'esprimono gli eventuali indici usati per identificare una 'proprietà '- SetValue(O, V, I()) : come prima, solo che V rappresenta 'il valore da assegnare PI.SetValue(S, Value,Nothing )Next Console.ReadLine()End Sub End Module
Completare i campi per l'oggetto Song: Titolo : Sinfonia n.5 in Dom Autore : Ludwig van BeethovenPrima di procedere nella seconda parte dell'esempio, è necessario dire una cosa: secondo i principi Microsoft, tutte le proprietà che sono impostate nel costruttore devono essere ReadOnly, mentre tutte le altre (opzionali), possono essere anche impostate manualmente. Potrebbe sorgere un dubbio: come si fa ad impostare manualmente una proprietà di attributo se non è possibile usarlo come variabile? In questo caso si utilizza una sintassi speciale, che ricorda un pò il Pascal, dove si assegna il valore con l'operatore :=:
<[Attributo]([Parametri costruttore], [Proprieta'] := [Valore])> _ [Membro]Ora bisogna aggiungere un altro membro a NameAttribute, che specifica se il campo sia obbligatorio oppure no: sarà una proprietà normale poichè non presenzia nei parametri del costruttore:
Module Module1Class NameAttributeInherits AttributePrivate ReadOnly _NameAs String Private _IsCompulsoryAs Boolean = FalsePublic ReadOnly Property Name()As String Get Return _NameEnd Get End Property Public Property IsCompulsory()As Boolean Get Return _IsCompulsoryEnd Get Set (ByVal ValueAs Boolean ) _IsCompulsory = ValueEnd Set End Property Sub New (ByVal NameAs String ) _Name = NameEnd Sub End Class Class SongPrivate _Title, _AuthorAs String 'Il titolo è obbligatorio <Name("Titolo", IsCompulsory:=True)> _Public Property Title()As String Get Return _TitleEnd Get Set (ByVal ValueAs String ) _Title = ValueEnd Set End Property 'Se non specificato, IsCompulsory = False <Name("Autore")> _Public Property Author()As String Get Return _AuthorEnd Get Set (ByVal ValueAs String ) _Author = ValueEnd Set End Property End Class Sub Main()Dim SAs New SongDim SongTypeAs Type = GetType(Song)Dim NameTypeAs Type = GetType(NameAttribute)Dim AttrAs NameAttribute Console.WriteLine("Completare i campi per l'oggetto Song:") Console.WriteLine("L'asterisco indica quelli obbligatori:") Console.WriteLine()For Each PIAs PropertyInfoIn SongType.GetProperties() Attr = TryCast(PI.GetCustomAttributes(NameType, False)(0), _ NameAttribute)If AttrIs Nothing Then Continue For End If Dim ValueAs Object Console.Write(Attr.Name)If Attr.IsCompulsoryThen 'Asterisco se è obbligatorio Console.Write("*")End If Console.Write(": ") 'Legge il valore Value = Console.ReadLine 'Se Value è una stringa vuota, ma è obbligatoria, la richiede 'all'inifnito, fino a quanto l'utente non immette un 'valore corretto If Attr.IsCompulsoryAndAlso Value = ""Then While Value = "" Console.WriteLine("Questa proprietà è obbligatoria!") Console.Write("Reimmettere il valore corretto: ") Value = Console.ReadLineEnd While End If PI.SetValue(S, Value,Nothing )Next Console.ReadLine()End Sub End Module
The Totem's Lair - Copyright (C) 2009
È vietata la riproduzione sia totale che parziale del sito.



