Le migliorate funzionalità di Visual Basic 2005

Visual Studio 2005

In questo articolo sono descritti i numerosi miglioramenti apportati in Visual Basic 2005 e vengono forniti semplici esempi di codice per illustrarne il funzionamento. Le caratteristiche descritte includono i commenti XML, i generics, la parola chiave Global, i tipi parziali e la gerarchia My (20 pagine stampate).

ms379584.3squares(it-it,VS.80).gif

In questa pagina

 Introduzione
 Gerarchia My
 Commenti XML
 Generics
 Istruzione Using
 Istruzione Continue
 Parola chiave Global
 Operatore IsNot
 Istruzione TryCast
 Overload dell'operatore e operatori di conversione
 Accessibilità delle funzioni di accesso alle proprietà
 Funzioni di accesso agli eventi personalizzati
 Tipi parziali
 Eventi a livello di applicazione
 Tipi senza segno
 Istanze predefinite
 Avvisi del compilatore
 Limiti di matrice espliciti
 Conclusioni

Introduzione

I principali cambiamenti apportati al linguaggio Visual Basic includono la gerarchia My, i commenti XML e i generics. A livello di logica sono disponibili numerose nuove istruzioni come Using, Continue e TryCast, oltre alla parola chiave Global. Sono stati apportati molti miglioramenti strutturali, incluse modifiche all'accessibilità delle funzioni di accesso alle proprietà, funzioni di accesso agli eventi personalizzati, tipi parziali ed eventi a livello di applicazione. L'overload dell'operatore e gli operatori di conversione costituiscono delle novità di questa versione, così come l'operatore IsNot. Altri importanti cambiamenti riguardano i tipi senza segno, le istanze predefinite dei form, gli avvisi del compilatore e i limiti di matrice espliciti.

Al primo avvio di Visual Studio 2005, viene richiesto di selezionare le impostazioni preferite per l'ambiente IDE. Queste impostazioni controllano funzionalità come il mapping dei tasti di scelta rapida per l'IDE, i layout delle finestre e la formattazione del codice nell'editor. Le impostazioni possono essere modificate in qualsiasi momento scegliendo Import/Export Settings dal menu Tools, come illustrato nella figura 1. È possibile importare impostazioni predefinite per un altro linguaggio di programmazione o file di impostazioni personalizzate utilizzati da tutti gli sviluppatori di un'organizzazione.

ms379584.languageenhancements-fig1(it-it,VS.80).gif

Figura 1. Importazione di impostazioni personalizzate per standardizzare l'ambiente di sviluppo a livello di organizzazione.

Gerarchia My

Le dimensioni di .NET Framework e il numero elevato di classi nella gerarchia del suo spazio dei nomi rappresentano uno dei principali problemi per gli sviluppatori che eseguono la migrazione a .NET da Visual Basic 6.0 o versioni precedenti. Gli oggetti di utilizzo frequente per le applicazioni e l'ambiente sono disponibili all'interno della libreria di classi base, o BCL (Base Class Library), di .NET Framework e per apprenderne le posizioni è necessario un certo tempo. La nuova gerarchia My di Visual Basic 2005 rende più semplice e rapido lo sviluppo delle applicazioni, offrendo una posizione pratica e organizzata in modo logico per accedere a numerose classi utilizzate di frequente.

Le funzionalità My sono disponibili in due modalità:

  • Elementi che forniscono collegamenti ben organizzati alle classi di .NET Framework.

  • Un set di oggetti dinamici creati quando si aggiungono form, impostazioni, risorse e Web service ai progetti.

I collegamenti My offrono una soluzione per accedere rapidamente a numerosi oggetti BCL utilizzati di frequente. I collegamenti My di primo livello sono My.Application, My.Computer e My.User, ognuno dei quali contiene una propria gerarchia di oggetti. L'oggetto My.Computer, ad esempio, espone Audio, FileSystem, Keyboard, Mouse, Network,Registry e altri elementi:

Dim sVar As String
sVar = My.User.Identity.Name
sVar = My.Computer.Info.OSFullName
sVar = My.Application.CommandLineArgs.Count.ToString

Gli oggetti dinamici My vengono popolati automaticamente in Visual Basic quando si aggiungono form, risorse, impostazioni e Web service ai progetti. My.Resources e My.Settings sono particolarmente interessanti, perché il compilatore di Visual Basic genera riferimenti a variabili fortemente tipizzate quando vengono aggiunte risorse e impostazioni al progetto.

Fare doppio clic su My Project in Solution Explorer per visualizzare la finestra Application Designer, quindi fare clic su Settings nell'elenco delle schede, come illustrato nella figura 2.

ms379584.languageenhancements-fig2(it-it,VS.80).gif

Figura 2. Scheda Settings di Application Designer. Nel riquadro Error List, ora separato da Task List, sono visualizzati errori, avvisi e messaggi.

Aggiungere un nome di impostazione come MaxInputValue di tipo Integer in ambito utente, con un valore di 100. È immediatamente possibile fare riferimento a questa impostazione nel codice utilizzando un oggetto fortemente tipizzato con un completo supporto IntelliSense, come illustrato nella figura 3.

ms379584.languageenhancements-fig3(it-it,VS.80).gif

Figura 3. Esempio di popup IntelliSense per un valore Settings creato in Application Designer.

Nell'angolo superiore destro della finestra di progettazione Settings è presente un collegamento denominato View Code. Fare clic su questo collegamento per visualizzare il file Settings.vb.

Questo file è una classe parziale in cui è possibile aggiungere codice per gestire eventi di impostazione, in modo da aggiornare lo stato dell'applicazione quando cambiano le impostazioni (vedere la sezione Tipi parziali per ulteriori informazioni):

Partial Friend NotInheritable Class MySettings
    '...
End Class

Qui sono esposti quattro eventi MySettings:

  • PropertyChanged

  • SettingChanging

  • SettingsSaving

  • SettingsLoaded

L'interfaccia Settings per le applicazioni è collegabile, nel senso che l'implementazione di queste routine di gestione degli eventi consente di definire in che modo devono essere salvate le impostazioni.

Si ottiene la stessa tipizzazione con le risorse aggiunte al progetto. Se si trascina un'immagine denominata Happy.bmp nell'area Images della finestra di progettazione Resources, è possibile farvi riferimento nel codice come My.Resources.Happy. L'immagine Happy è di tipo Bitmap, pertanto non è necessario eseguire il cast da un tipo Object o Image per utilizzare la bitmap nel codice. Inoltre il supporto IntelliSense è immediatamente disponibile quando si digita Happy nel codice. Ad esempio:

<span style='mso-fareast-font-family:
"Times New Roman";mso-ansi-language:IT'>PictureBox1.Image = My.Resources.HAPPY<o:p></o:p></span>

Questa riga di codice assegna l'oggetto bitmap a una proprietà Image di PictureBox. Nella figura 4 è illustrata la finestra popup IntelliSense, che indica che l'oggetto è di tipo Bitmap.

ms379584.languageenhancements-fig4(it-it,VS.80).gif

Figura 4. Il trascinamento di un'immagine bitmap nella scheda Resources di Application Designer produce un oggetto fortemente tipizzato che è possibile utilizzare immediatamente nel codice.

Quando si aggiungono form e Web service al progetto, l'oggetto My viene popolato in modo dinamico con istanze predefinite fortemente tipizzate di questi oggetti, a cui è possibile fare riferimento nel codice.

Come si può notare, la gerarchia My rende più semplice trovare le classi BCL relative all'ambiente e alle applicazioni, fornendo un accesso immediato a impostazioni, risorse e altri oggetti aggiunti al progetto. Si tratta di importanti miglioramenti per la produttività, utili agli sviluppatori Visual Basic di qualsiasi livello.

Commenti XML

I commenti XML consentono di aggiungere una documentazione strutturata al codice e rappresentano una funzionalità molto richiesta dagli sviluppatori Visual Basic, dal momento che sono stati introdotti prima in C#. I commenti XML possono descrivere un'ampia varietà di elementi di codice come classi, campi, metodi ed enumerazioni.

Una volta creato un commento XML che descrive una caratteristica del codice, è immediatamente possibile sfruttare le funzionalità IntelliSense per i parametri e il tipo restituito quando si digita il codice nell'editor. Si supponga di avere un prototipo di funzione con la seguente firma:

Private Function GetCustomerData(ByVal CustomerCode As String) _
    As DataSet

Posizionare il punto di inserimento del codice sulla riga sopra la dichiarazione di funzione e digitare tre virgolette singole. Visual Basic genera un modello di commento XML che corrisponde alla dichiarazione di funzione, in cui è possibile spostarsi premendo TAB e che può essere compilato come un form. Si supponga di compilare il modello di commento per la funzione come segue:

''' <summary>
''' Returns a DataSet for a single customer.
''' </summary>
''' <param name="CustomerCode">Customer Code as String.</param>
''' <returns>DataSet for the supplied CustomerCode.</returns>
''' <remarks>Resides in the application's data layer.</remarks>

Quando si digita questo nome di funzione in qualsiasi punto del codice, è possibile sfruttare un completo supporto IntelliSense per il riepilogo, i parametri e il valore restituito della funzione, come illustrato nella figura 5.

ms379584.languageenhancements-fig5(it-it,VS.80).gif

Figura 5. In questo popup vengono visualizzate in modo immediato le informazioni IntelliSense quando si aggiungono commenti XML agli elementi di codice.

Si tratta di una caratteristica di importanza chiave a livello di organizzazione e team. È possibile generare documentazione del codice dai commenti XML strutturati inseriti nei file di origine. Inoltre, un progettista di applicazioni o un responsabile dello sviluppo può realizzare prototipi e commentare funzionalità prima dell'implementazione. Quando gli sviluppatori scrivono il codice utilizzando gli oggetti prototipo, IntelliSense li assiste nel corretto utilizzo delle funzionalità.

I commenti XML sono gestiti dal compilatore come parte integrante del codice. I valori dei tag dei commenti sono colorati come i commenti e se si comprime la struttura in un commento XML viene visualizzato solo il valore del tag Summary invece dell'intero modello di commento XML (figura 6).

ms379584.languageenhancements-fig6(it-it,VS.80).gif

Figura 6. I commenti XML sono completamente integrati con il compilatore e la finestra del codice. Il commento XML per la funzione FillDataGrid è compresso in modo da visualizzare la riga Summary.

Se nel prototipo di funzione si cambia il nome del parametro CustomerCode in CustomerID, il compilatore visualizza una linea ondulata di colore verde sotto il tag

<param name="CustomerCode">
per segnalare che i due nomi non corrispondono (vedere la sezione per ulteriori informazioni).

In Visual Basic viene creato automaticamente un file di documentazione XML quando si genera il progetto. Questo file viene visualizzato nella directory di output dell'applicazione come AssemblyName.xml. Poiché il file è in formato XML, può essere facilmente trasformato in altri formati di output in base alle esigenze. I commenti XML rendono molto più semplice e pratico generare documentazione del codice, sia in termini di supporto IntelliSense durante la scrittura, sia come documentazione dopo la generazione dell'applicazione.

Generics

La libreria di classi base ora fornisce lo spazio dei nomi System.Collections.Generic, in cui sono contenute diverse classi che definiscono insiemi generici. Vengono definiti " generics" perché nella dichiarazione si specifica un segnaposto di tipo per gli oggetti contenuti invece di un tipo specifico. Agli oggetti memorizzati viene attribuito un tipo specifico solo quando si crea un'istanza dell'insieme.

I generics assicurano un notevole risparmio di tempo. Chi ha provato a creare insiemi personalizzati sa che può essere necessaria una grande quantità di codice. I generics di Visual Basic consentono di creare l'equivalente di un insieme personalizzato con una sola riga di codice. Non è più necessario creare insiemi personalizzati distinti per ciascun tipo di oggetto che si desidera memorizzare. È sufficiente fornire il tipo desiderato quando si crea un'istanza dell'insieme generico.

Il modo più semplice per comprendere come funzionano i generics è ricorrere a un esempio. Si supponga di avere una semplice classe Customer con due proprietà pubbliche (mostrate come variabili pubbliche per brevità):

Public Class Customer
    Public Name As String
    Public CreditLimit As Decimal

    Public Sub New(ByVal CustomerName As String, _
      ByVal CustCreditLimit As Decimal)
        Name = CustomerName
        CreditLimit = CustCreditLimit
    End Sub
End Class

È possibile dichiarare un elenco di clienti utilizzando la classe di insieme generico List, come segue:

Dim Customers As New System.Collections.Generic.List(Of Customer)

Con questa singola riga di codice si dichiara un elenco fortemente tipizzato che memorizza solo i tipi Customer e offre un completo supporto IntelliSense per gli oggetti Customer contenuti. Altrettanto facilmente è possibile creare un elenco di oggetti Product o Order, in modo da definire un set di insiemi personalizzati senza scrivere tutto il codice dell'insieme personalizzato per ciascun tipo. È ora possibile scrivere codice come quello riportato di seguito:

Dim custA As New Customer("CustA", 1000)
Customers.Add(custA)
Dim custB As New Customer("CustB", 2000)
Customers.Add(custB)
For Each c As Customer In Customers
    MessageBox.Show("Customer: " & c.Name & _
      ", limit: " & c.CreditLimit)
Next

'compile error: Product cannot be converted to Customer
Dim prodA As New Product("ProdA", CDec(29.95))
Customers.Add(prodA)

L'utilizzo degli insiemi generici migliora anche le prestazioni perché gli oggetti memorizzati sono fortemente tipizzati e non vengono mantenuti internamente come tipo Object.

Sono disponibili altri insiemi generici nello spazio dei nomi System.Collections.Generic. Ad esempio, l'insieme Dictionary(of K,V) consente di specificare tipi per le chiavi e i valori. Gli insiemi generici LinkedList(of T) e Stack(of T) funzionano come normali elenchi collegati e stack, ma consentono di specificare i tipi di oggetti che contengono.

È possibile creare tipi generici personalizzati utilizzando la nuova sintassi di dichiarazione per i tipi generici. Si consideri una classe Comparer che consente di confrontare diversi tipi di oggetti:

Public Class Comparer(Of itemType)
    '...
End Class

È possibile definire segnaposti per più tipi in un elenco separato da virgole, oltre che definire vincoli per limitare le classi che possono essere fornite al tipo generico quando si crea un'istanza:

Public Class Comparer(Of itemType As IComparable)
    '...
End Class

Questo vincolo assicura che le istanze Comparer(of T) possano essere create solo con classi che implementano l'interfaccia IComparable. È anche possibile applicare più vincoli alla dichiarazione di classe.

A titolo di esempio, si consideri una classe Customers espansa che implementa IComparable:

Public Class Customer
    Implements IComparable
    Public Name As String
    Public CreditLimit As Decimal

    Public Sub New(ByVal CustomerName As String, _
      ByVal CustCreditLimit As Decimal)
        Name = CustomerName
        CreditLimit = CustCreditLimit
    End Sub

    Public Function CompareTo(ByVal obj As Object) As Integer _
      Implements IComparable.CompareTo
        Dim c As Customer = CType(obj, Customer)
        If CreditLimit > c.CreditLimit Then Return 1
        If CreditLimit < c.CreditLimit Then Return -1
        Return 0
    End Function
End Class

Viene implementata una classe Product simile, tranne per il fatto che la funzione CompareTo confronta i prezzi dei prodotti invece dei limiti di credito dei clienti:

Public Class Product
    Implements IComparable
    Public Name As String
    Public Price As Decimal

    Public Sub New(...)...
    Public Function CompareTo(...)...
End Class

Ora la classe Comparer fornisce l'operatore di confronto generico:

Public Class Comparer(Of itemType As IComparable)
    Public Function GetLargest(ByVal Item1 As itemType, _
    ByVal Item2 As itemType) As itemType
        Dim i As Integer = Item1.CompareTo(Item2)
        If i > 0 Then Return Item1
        If i < 0 Then Return Item2
        Return Nothing
    End Function
End Class

È ora possibile creare istanze di Comparer con oggetti di diversi tipi:

Dim pc As New Comparer(Of Product)
Dim prod1 As New Product("LittleOne", 10)
Dim prod2 As New Product("BigOne", 100)
Dim lp As Product = pc.GetLargest(prod1, prod2)
MessageBox.Show("The more expensive product is: " & lp.Name)

Dim cc As New Comparer(Of Customer)
Dim cust1 As New Customer("SmallCo", 1000)
Dim cust2 As New Customer("LargeCo", 5000)
Dim lc As Customer = cc.GetLargest(cust1, cust2)
MessageBox.Show("The customer with a higher limit is: " & lc.Name)

Senza i generics sarebbe necessario definire una classe di confronto per ciascun tipo di oggetto da confrontare, come ad esempio ProductComparer e OrderComparer.

I generics possono ridurre notevolmente le attività di codifica in numerosi scenari comuni. È consigliabile utilizzare i generics quando si dispone di più classi che variano solo per il tipo di oggetto su cui operano.

Istruzione Using

L'istruzione Using offre una pratica soluzione per acquisire un oggetto, utilizzarlo per eseguire del codice e rilasciarlo immediatamente. Numerosi oggetti di .NET Framework, come immagini, handle di file, porte di comunicazione e connessioni SQL, richiedono di rilasciare gli oggetti creati per evitare perdite di memoria nelle applicazioni. Si supponga di voler disegnare un rettangolo utilizzando un oggetto Brush:

Using g As Graphics = Me.CreateGraphics()
    Using br As System.Drawing.SolidBrush = _
        New SolidBrush(System.Drawing.Color.Blue)
        g.FillRectangle(br, New Rectangle(30, 50, 230, 200))
    End Using
End Using

Si desidera eliminare le immagini e gli oggetti Brush al termine del loro utilizzo: l'istruzione Using permette di eseguire questa operazione molto velocemente. L'istruzione Using offre un metodo molto più semplice rispetto all'utilizzo di Try / Catch e al rilascio dell'oggetto nel blocco Finally, come è necessario in Visual Basic .NET (versione 2002 e 2003).

Istruzione Continue

L'istruzione Continue passa all'iterazione successiva di un ciclo, rendendo la logica del ciclo più concisa e leggibile:

Dim j As Integer
Dim prod As Integer
For i As Integer = 0 To 100
    j = 0
    While j < i
        prod = i * j
        If prod > 5000 Then
            'skips to the next For value
            Continue For
        End If
        j += 1
    End While
Next

L'istruzione Continue è molto efficace e rende piuttosto semplice l'escape del ciclo interno, senza ricorrere a un'etichetta e a un'istruzione goto. È possibile utilizzare l'istruzione Continue per i cicli For, While e Do.

Parola chiave Global

La parola chiave Global rende accessibile lo spazio dei nomi principale, o vuoto, al primo livello della gerarchia degli spazi dei nomi. In passato non era possibile definire uno spazio dei nomi System.IO all'interno della gerarchia degli spazi dei nomi dell'organizzazione:

Namespace MyCompany.System.IO

Questo renderebbe ambigui tutti i riferimenti allo spazio dei nomi System di .NET Framework all'interno dell'applicazione. Ora è possibile utilizzare la parola chiave Global per eliminare l'ambiguità dagli spazi dei nomi:

Dim myFile As Global.System.IO.File

La parola chiave Global è particolarmente utile negli scenari di generazione del codice in cui è necessario essere assolutamente certi che i riferimenti allo spazio dei nomi generati puntino agli elementi desiderati. Lo stesso Visual Basic utilizzerà la parola chiave Global in tutto il codice generato.

Operatore IsNot

L'operatore IsNot rappresenta la controparte dell'operatore Is. IsNot consente di utilizzare un confronto diretto, eliminando l'operatore Not:

If myObj IsNot Nothing Then

Analogamente, è possibile eliminare l'operatore Not quando si verifica se due istanze di oggetti sono differenti:

If MyObj1 IsNot MyObj2 Then

Anche se può apparire un cambiamento di piccola entità, IsNot colma un gap a livello di uniformità nel linguaggio Visual Basic che rende il codice più semplice.

Istruzione TryCast

In Visual Basic 2003 esistono due metodi per eseguire il cast di un tipo di oggetto a un altro tipo:

Dim p As Product 
p = CType(obj, Product)
p = DirectCast(obj, Product)

È possibile utilizzare CType per convertire un tipo in un altro, mentre DirectCast richiede una relazione di ereditarietà o implementazione tra gli oggetti. Il problema di questi metodi è che viene generata un'eccezione in fase di esecuzione se non è possibile convertire o eseguire il cast di

obj
nel tipo Product.

Ora è possibile utilizzare la nuova istruzione TryCast. Questa istruzione viene utilizzata nello stesso modo di CType o DirectCast, tranne per il fatto che il risultato restituito è

Nothing
se non è possibile eseguire il cast:
p = TryCast(obj, Product)
If p IsNot Nothing Then
    'use the p object...
End If

Overload dell'operatore e operatori di conversione

Una delle più potenti nuove caratteristiche di Visual Basic 2005 è l'overload dell'operatore, che consente di definire operatori che agiscono su qualsiasi tipo desiderato, inclusi i tipi base personalizzati.

Un tipico esempio di overload dell'operatore riguarda l'aggiunta di numeri complessi. Una classe Complex semplificata con overload dell'operatore + potrebbe avere il seguente aspetto:

Public Class Complex
    Public Real As Double
    Public Imag As Double

    Public Sub New(ByVal realPart As Double, ByVal imagPart As Double)
        Real = realPart
        Imag = imagPart
    End Sub

    Shared Operator +(ByVal lhs As Complex, ByVal rhs As Complex) _
        As Complex
        Return New Complex(lhs.Real + rhs.Real, lhs.Imag + rhs.Imag)
    End Operator
End Class

L'operatore + può essere utilizzato per aggiungere numeri complessi in modo molto intuitivo:

Dim lhs As Complex = New Complex(2.0, 2.5)
Dim rhs As Complex = New Complex(3.0, 3.5)
Dim res As Complex = lhs + rhs
'res.real = 5.0, res.imag = 6.0

È anche possibile eseguire l'overload di operatori di conversione per tipi personalizzati. Se si tenta di convertire il valore di

res
come CType(res,String), viene generato un errore del compilatore che segnala che è impossibile convertire
Complex
in
String
. Se si tenta di controllare il valore di
Res.ToString
, si ottiene un valore di
Complex
poiché ToString mostra il nome del tipo per impostazione predefinita. È possibile risolvere questi problemi eseguendo l'overload dell'operatore di conversione CType e del metodo ToString, come segue:
Public Shared Narrowing Operator CType(ByVal Value As Complex) _
    As String
    Return Value.Real.ToString & "i" & Value.Imag.ToString
End Operator

Public Overrides Function ToString(ByVal Value As Complex) As String
    Return Value.Real.ToString & "i" & Value.Imag.ToString
End Function

Ora i valori restituiti da CType(res,String) e

res.ToString
sono quelli previsti: "5.0i6.0." Gli operatori di conversione devono essere dichiarati con Narrowing o Widening, in modo da indicare come viene effettuata la conversione.

Accessibilità delle funzioni di accesso alle proprietà

Un problema che si presenta spesso agli sviluppatori alle prese con le proprietà di Visual Basic .NET è il fatto che le funzioni di accesso Get e Set devono avere la stessa accessibilità (Public, Friend o Private). Se si desidera creare una proprietà in sola lettura pubblica (solo Get è pubblica), non è disponibile alcuna funzione di accesso Set utilizzabile all'interno del componente per applicare la convalida o la gestione della proprietà personalizzata.

In Visual Basic 2005 le funzioni di accesso Get e Set hanno differenti impostazioni di accessibilità, a condizione che Set sia più restrittiva di Get:

Private _myProp As String
Public Property MyProp() As String
    Get
        Return _myProp
    End Get
    Friend Set(ByVal value As String)
        If value.Trim.Length > 0 Then
            _myProp = value.Trim
        Else
            value = "<no value>"
        End If
    End Set
End Property

Questa nuova caratteristica è particolarmente utile per i team di sviluppo e i singoli sviluppatori che desiderano ottenere il massimo in termini di riutilizzo del codice.

Funzioni di accesso agli eventi personalizzati

Le funzioni di accesso agli eventi consentono di definire un evento personalizzato e controllare che cosa accade quando i client aggiungono e rimuovono gestori e generano l'evento. Si supponga di avere una classe personalizzata in cui si genera un evento RateChanged. Esistono due metodi per dichiarare eventi normali:

Public Event RateChanged()
  'or
Public Event HoursChanged As EventHandler

Gli eventi dichiarati in questo modo dispongono di un archivio di backup gestito automaticamente. In altre parole, il sistema definisce come l'evento viene gestito e inviato. In genere questo approccio funziona, ma talvolta è necessario un maggiore controllo sulle modalità di notifica dei listener dell'evento.

Ora è possibile dichiarare un evento personalizzato e le relative funzioni di accesso utilizzando la nuova parola chiave Custom. Quando si preme il tasto INVIO nella dichiarazione di evento, Visual Basic 2005 crea automaticamente il prototipo di codice nello stesso modo in cui vengono generate le funzioni di accesso Property:

Public Custom Event NameChanged As EventHandler
    AddHandler(ByVal value As EventHandler)
        'hook handler to backing store
    End AddHandler

    RemoveHandler(ByVal value As EventHandler)
        'remove handler from backing store
    End RemoveHandler

    RaiseEvent(ByVal sender As Object, ByVal e As EventArgs)
        'invoke listeners
    End RaiseEvent
End Event

Quando il client aggiunge o rimuove un gestore per l'evento, viene eseguita la routine AddHandler o RemoveHandler. Al momento della generazione dell'evento, viene eseguita la routine RaiseEvent. In questo modo, è possibile eseguire specifiche operazioni in base a come si desidera gestire l'archivio di backup per l'evento. Quando si crea un evento personalizzato con questo metodo, l'evento può essere considerato come una proprietà.

Questa soluzione è ad esempio utile quando un oggetto è serializzabile e si dispone di un evento gestito da un oggetto delegato non serializzabile. Se si tenta di serializzare l'oggetto con un evento normale, la serializzazione ha esito negativo perché l'archivio di backup dell'evento non è serializzabile. Rocky Lhotka (un altro Visual Basic MVP) fornisce una spiegazione di questo comportamento con un esempio dettagliato nel suo blog all'indirizzo http://www.lhotka.net/WeBlog/CommentView.aspx?guid=776f44e8-aaec-4845-b649-e0d840e6de2c. (informazioni in lingua inglese)

Tipi parziali

I tipi parziali consentono di definire un singolo tipo tra più file di origine. La definizione del tipo ha una normale dichiarazione in un solo file:

Public Class TestPartial
    'implementation...
End Class

Negli altri file di origine si utilizza la parola chiave Partial per comunicare al compilatore che il codice è una continuazione della definizione di classe originale:

Partial Public Class TestPartial
    'implementation...
End Class

Il codice nelle classi generate dalle finestre di progettazione dell'IDE è contrassegnato dalla parola chiave Partial ed è separato dal codice utente. Se si aggiunge a un progetto un form denominato TestForm e si esamina il file di origine risultante, si può restare sorpresi constatando che il file non contiene alcun elemento ad eccezione della dichiarazione di classe del form. Dove si trova tutto il codice generato dalla finestra di progettazione che in precedenza era posizionato all'interno dell'area Windows Form Designer Generated Code?

Il codice generato dalla finestra di progettazione è ora posizionato nel file TestForm.designer.vb, che è possibile osservare facendo clic sul pulsante Show All Files nella barra degli strumenti di Solution Explorer. È consigliabile evitare di modificare il codice in questo file, tuttavia è possibile copiare e incollare gli elementi desiderati nel file TestForm.vb se si desidera preservarli quando il file della finestra di progettazione viene nuovamente generato.

I team che lavorano a un progetto possono trarre vantaggio dalle classi parziali fornendo a ogni sviluppatore un file che contiene una specifica porzione della classe. Non è più necessario che diversi sviluppatori condividano l'accesso agli stessi file di origine, dal momento che ora è possibile suddividere una definizione di classe in più file di origine.

Eventi a livello di applicazione

Un'altra caratteristica da cui gli sviluppatori possono trarre vantaggio è un nuovo set di eventi a livello di applicazione disponibili in una classe parziale denominata MyApplication. Individuare il file ApplicationEvents.vb al di sotto del progetto, o il file Application.Designer.vb al di sotto dell'elemento My Project in Solution Explorer. È anche possibile trovare questo file dietro il pulsante View Application Events nella scheda Application di Application Designer.

Questi nuovi eventi a livello di applicazione sono simili agli eventi dell'applicazione nel file global.asax in un'applicazione ASP.NET. Vengono esposti cinque eventi:

  • Shutdown

  • Startup

  • StartupNextInstance

  • NetworkAvailabiltyChanged

  • UnhandledException

I primi tre eventi vengono generati all'avvio e all'arresto dell'applicazione. NetworkAvailabilityChanged viene generato quando cambia lo stato della rete nel computer. È possibile inserire del codice nell'evento UnhandledException nel caso venga generata un'eccezione che non è gestita altrove.

Tipi senza segno

Visual Basic 2005 offre un completo supporto per i tipi senza segno. I nomi dei tipi senza segno sono:

  • SByte

  • UShort

  • UInteger

  • ULong

I tipi senza segno funzionano come tipi normali tranne per il fatto che sono in grado di memorizzare solo Integer positivi.

I tipi senza segno sono estremamente utili in Visual Basic per eseguire chiamate alle API Win32 che accettano come parametri tipi senza segno. Il codice seguente illustra una chiamata alla API MessageBox di Windows:

Public Enum WindowsMessageResult As UInteger
    OK = 1
    Cancel = 8
End Enum

Private Const MB_OK As UInteger = 0
Private Const MB_ICONEXCLAMATION As UInteger = &H30
Private Const MB_OPTIONS As UInteger = MB_OK Or MB_ICONEXCLAMATION

Private Declare Auto Function Win_MB Lib _
    "user32.dll" Alias "MessageBox" _
    (ByVal hWnd As Integer, ByVal lpText As String, _
    ByVal lpCaption As String, ByVal uType As UInteger) _
    As UInteger

Public Function MessageThroughWindows(ByVal message As String, _
    ByVal caption As String) As WindowsMessageResult
    Dim r As UInteger = Win_MB(0, message, caption, MB_OPTIONS)
    Return CType(r, WindowsMessageResult)
End Function

Si noti che l'ultimo parametro e il tipo restituito nella dichiarazione Win_MB sono entrambi tipi UInteger.

I tipi senza segno sono anche utili per risparmiare memoria se è necessario memorizzare valori più grandi di un Integer. Il tipo Integer utilizza quattro byte di memoria e può memorizzare valori positivi e negativi fino a 2.147.483.648. Anche il tipo UInteger utilizza quattro byte ed è in grado di memorizzare un valore compreso tra zero e 4.294.967.295. In assenza di un tipo senza segno sarebbe necessario utilizzare un tipo Long che richiede otto byte di memoria per memorizzare valori così grandi.

Istanze predefinite

Un altro cambiamento apportato a Visual Basic .NET che è risultato in qualche modo problematico per numerosi sviluppatori in seguito alla migrazione da Visual Basic 6.0 è la mancanza di un'istanza predefinita per i form. È necessario creare un'istanza del form prima di utilizzarlo:

Dim frm As New Form2
frm.Show()

Dal momento che Visual Basic 2005 supporta le istanze predefinite dei form, è possibile utilizzare la familiare sintassi:

Form2.Show()

La soluzione migliore è accedere a questa istanza di form predefinita tramite l'insieme My.Forms:

My.Forms.Form2.Show()

Avvisi del compilatore

Visual Basic 2005 supporta gli avvisi del compilatore, che forniscono informazioni sui problemi che possono verificarsi in fase di esecuzione. Un avviso viene mostrato sotto forma di una linea verde ondulata al di sotto del codice, mentre gli errori sono di colore blu.

Gli avvisi del compilatore includono l'accesso ricorsivo alle proprietà, la sovrapposizione di blocchi catch o di istruzioni case e la creazione di una funzione senza un valore restituito. L'avviso che preferisco riguarda un riferimento di variabile a un oggetto non inizializzato:

Dim cust As Customer
If cust.Name.Length = 0 Then
  '...
End If

In questo caso, il compilatore in background inserisce una linea verde ondulata sotto

cust
nell'istruzione
If
. Il testo dell'avviso visualizzato è "variable 'cust' is used before it has been assigned a value". In fase di esecuzione, il risultato può essere un'eccezione di riferimento null. In passato mi è capitato molte volte di rilevare questo tipo di errore in fase di esecuzione e ora il compilatore consente di identificarlo in fase di compilazione.

Quando si digita il codice precedente nell'editor, il compilatore inizialmente inserisce una linea verde ondulata sotto

cust
nell'istruzione
Dim
con il messaggio "unused local variable 'cust'". In un primo momento questo può sembrare fastidioso perché la variabile è appena stata aggiunta ma in definitiva aiuta a mantenere il codice più pulito.

Invece di mostrare tutti gli errori in Task List nell'IDE, è disponibile una nuova finestra Errors List che separa i messaggi in errori, avvisi e messaggi (figure 2 e 6). È possibile specificare se il compilatore deve segnalare gli avvisi o gli errori nella scheda Compile di Application Designer, in cui sono presenti caselle di controllo per indicare di disattivare tutti gli avvisi o di trattare tutti gli avvisi come errori.

È possibile utilizzare l'istruzione Option Strict On per generare errori in fase di compilazione per varie situazioni. Option Strict segnalerà il codice se si tenta di eseguire una conversione verso un tipo di dati più piccolo, che potrebbe comportare una perdita di dati:

Dim iValue As Integer
Dim lValue As Long
iValue = lValue     'narrowing conversion error
lValue = iValue     'ok

Viene generato un errore anche se si utilizza l'associazione tardiva. Un oggetto viene sottoposto ad associazione tardiva quando è assegnato a una variabile di tipo Object:

Dim myObj As Object
Call myObj.method1()    'late binding error

L'utilizzo di Option Strict è considerato una best practice per la programmazione in Visual Studio. È consigliabile attivare Option Strict nel codice ogni volta che è possibile. Option Strict può essere attivato scegliendo Options dal menu Tools, quindi selezionando la casella di controllo Option Strict nelle impostazioni Project. È anche possibile inserire l'istruzione Option Strict On all'inizio di una singola classe o di un file di modulo.

Limiti di matrice espliciti

Ora è possibile dichiarare matrici utilizzando limiti di matrice espliciti per rendere più chiara la dichiarazione:

Dim a(10) As Integer        'old way
Dim b(0 To 10) As Integer   'new way

I limiti di matrice in Visual Basic sono ancora a base zero, quindi verrà visualizzato un errore del compilatore se il valore dei limiti inferiori della matrice è diverso da 0.

Conclusioni

Il linguaggio Visual Basic 2005 include diverse importanti funzionalità e molti piccoli miglioramenti che aumentano notevolmente la facilità d'uso e la produttività degli sviluppatori. Il linguaggio è diventato più completo e più simile a C# per quanto riguarda alcune importanti caratteristiche come i commenti XML e l'overload dell'operatore.

Se a questo si aggiungono i numerosi miglioramenti apportati all'IDE, Visual Basic 2005 può essere considerato come la migliore versione di Visual Basic rilasciata finora. Non è solo migliore dal punto di vista del linguaggio, ma anche da quello della praticità di utilizzo. Sono certo che gli sviluppatori che lo proveranno non potranno che essere d'accordo.


Mostra: