Buone vacanze!

Negli USA sta per terminare l’anno fiscale, mentre a me sta terminando il lungo periodo lavorativo ed è giunta l’ora di fare un po’ di vacanza.

Venerdì 1 Luglio, infatti, partirò con mia moglie e con mio figlio in direzione Rimini (c/o l’Hotel Airone http://www.hotelairone.com, un ambiente tranquillo, a gestione familiare, con un’ottima cucina, un ottimo servizio e tanta amicizia!).

Non pubblicherò più nulla fino al mio rientro (16 Luglio) e quindi saluto tutti quelli che seguono i miei blog e auguro BUONE VACANZE A TUTTI!

 

Parallel computing e parallel programming

Se avete acquistato da poco un computer, avete anche la certezza di avere due o quattro unità di elaborazione (dual-core o quad-core), indipendentemente dal numero di processori e di core per ciascun processore presente sulla macchina.

In un futuro ormai prossimo, con il previsto avvento di processori multicore dotati di decine e decine di core (si parla già ora di processori in fase di produzione con 32 core e perfino con oltre 50 core), avremo una capacità di elaborazione estremamente potenziata rispetto ad oggi.

Dal punto di vista dell’utente vengono comunque considerati dei processori indipendenti e, quindi, utilizzerò il termine "processori" anche quando si tratta di core multipli all’interno di un unico processore.

Il problema, però, consiste nell’impossibilità di utilizzare a fondo le risorse a nostra disposizione e quindi di dividere il carico di lavoro tra tutti i processori disponibili, con il risultato di appesantire un unico processore e utilizzare più tempo per terminare un’attività.

Questo modo di lavorare è certamente comodo per il programmatore, perché scrivere un programma per un singolo processore è più semplice che dover governare anche la complessità della elaborazione concorrente. Del resto è il modo di lavorare che abbiamo sempre avuto fin dalla nascita dei personal computer.

Ora, però, abbiamo un hardware che ha un potenziale di elaborazione estremamente elevato e tutta questa potenza ha bisogno di strumenti di sviluppo adeguati per essere espressa realmente, altrimenti si vanificherebbero gli sforzi dei produttori di processori nel proporre prodotti all’avanguardia.

La parola d’ordine deve essere quindi parallel programming (sviluppo di programmi con attività svolte in parallelo), associata al termine parallel computing (esecuzione di uno o più programmi in parallelo su più processori).

Il concetto di programmazione parallela non è una novità, esiste già da tempo una formalizzazione del cosiddetto calcolo parallelo: nel 1967 fu pubblicata la "Legge di Amdahl" che indicava le basi ingegneristiche sia per l’elaborazione in cluster (elaborazione distribuita su più computer collegati fra loro, Figura 1),

 

01

 

sia per quella multiprocessore (elaborazione distribuita su più processori dello stesso computer, Figura 2).

02

 

Lo scenario che finora ci ha dato sicurezza, ma che ci ha anche limitati, è destinato a cambiare drasticamente. Infatti, il .NET Framework 4.0 ci ha portato una grande novità: la possibilità di creare programmi in grado di sfruttare tutti i processori disponibili.

Adesso la programmazione parallela è possibile anche con un comune personal computer, semplicemente utilizzando le librerie fornite con il .NET Framework 4.0 e quindi con Visual Studio 2010 e con i linguaggi Visual Basic e C#.

Questa nuova possibilità porta con sé molti vantaggi, tra i quali una maggiore scalabilità dei nostri programmi e migliori prestazioni (maggiore sfruttamento dell’hardware e minori tempi di esecuzione).

Occorre però precisare che la programmazione parallela ci offre il meglio di sé quando le elaborazioni possono essere suddivise su più processori e quando si tratta di elaborazioni sufficientemente "pesanti". Potrebbe, quindi, verificarsi il caso di un peggioramento delle prestazioni o, nel migliore dei casi, di prestazioni assolutamente equivalenti alla programmazione tradizionale (monoprocessore), quando l’applicazione richiede poche risorse o quando le istruzioni da eseguire solo talmente brevi da non far risultare conveniente questo approccio.

VB 2010: Optional Nullable Parameters e parametri denominati

I parametri opzionali sono dei parametri che vengono passati a un metodo e per i quali viene definito un valore di default. Se non viene passato un valore corrispondente a questi parametri, quindi, verrà utilizzato il valore di default.

Fino alla versione 2008 non era possibile passare un valore nullo, era necessario fornire sempre un valore valido. Dalla versione 2010 possiamo utilizzare un parametro Nullable, cioè un parametro che ammette il valore Nothing e che può essere verificato con l’operatore Is Nothing, come si può vedere dal codice seguente:

Visual Basic
  1.   Private Sub MetodoConParamNullable(
  2.       ByVal param1 As String,
  3.       Optional ByVal param2 As Integer? = Nothing)
  4.     If param2 Is Nothing Then
  5.       MessageBox.Show("Parametro nullo")
  6.     End If
  7.   End Sub

Un’altra caratteristica importante è la possibilità di utilizzare il nome di un parametro opzionale per assegnare un valore. Questo permette di non dover specificare tutti i parametri opzionali che precedono l’unico che vogliamo specificare. Per esempio:

Visual Basic
  1.   ' definiamo una funzione che restituisce
  2.   ' una stringa composta da altre tre stringhe
  3.   ' e con parametri opzionali
  4.   Public Function concatena(
  5.       Optional ByVal a As String = "a",
  6.       Optional ByVal b As String = "b",
  7.       Optional ByVal c As String = "c") As String
  8.     Return a & b & c
  9.   End Function
  10.  
  11.   ' proviamo la funzione …
  12.   Public Sub ParamDenominati()
  13.     ' … senza passare parametri
  14.     MessageBox.Show(concatena.ToString)
  15.     ' … passando solo il terzo parametro
  16.     MessageBox.Show(concatena(c:="x").ToString)
  17.     ' … passando solo il secondo parametro
  18.     MessageBox.Show(concatena(b:="y").ToString)
  19.   End Sub

Il risultato sarà costituito da tre messaggi, rispettivamente: "abc", "abx" e "ayc".

VB 2010: proprietà autoimplementate

Finora potevamo definire una proprietà solamente nel modo completo, indicando le sezioni Get e Set, anche se l’unica funzione di tali sezioni era assegnare e leggere la variabile interna:

Visual Basic
  1.   Private _miaProprieta As String
  2.   Public Property miaProprieta() As String
  3.     Get
  4.       Return _miaProprieta
  5.     End Get
  6.     Set(ByVal Value As String)
  7.       _miaProprieta = Value
  8.     End Set
  9.   End Property

In effetti, anche lo snippet specifico per le proprietà, che si inserisce scrivendo Property in una riga vuota e premendo il tasto per la tabulazione, definisce il seguente codice (con gli opportuni segnaposti per l’inserimento dei nomi desiderati):

Visual Basic
  1.   ' snippet Property
  2.   Private newPropertyValue As String
  3.   Public Property NewProperty() As String
  4.     Get
  5.       Return newPropertyValue
  6.     End Get
  7.     Set(ByVal value As String)
  8.       newPropertyValue = value
  9.     End Set
  10.   End Property

Ora, se non abbiamo la necessità di specificare ulteriore codice all’interno delle sezioni Get e Set, possiamo definire una proprietà in modo abbreviato:

Visual Basic
  1. Public Property miaProprieta As String

 

Questo stesso codice si ottiene utilizzando la nuova funzione per l’autogenerazione delle proprietà.

Con la stessa istruzione possiamo anche assegnare un valore alla proprietà:

Visual Basic
  1. Public Property miaProprieta As String = "Semplice vero?"

 

L’aspetto interessante di questa nuova implementazione è dato dal fatto che viene definita, in modo implicito, una variabile privata con lo stesso nome della proprietà, prefissato dal carattere underscore ("_"). Nel caso dell’esempio che abbiamo appena fatto, quindi, viene definita una variabile privata di tipo String e di nome _miaProprieta.

Questo automatismo è dimostrato dall’errore che viene visualizzato da IntelliSense quando definiamo a nostra volta una variabile con lo stesso nome.

Rimane l’obbligo di scrivere per esteso la definizione delle proprietà a sola lettura o a sola scrittura, dato che è necessario specificare tali caratteristiche con le parole riservate ReadOnly e WriteOnly:

Visual Basic
  1.   ' proprieta' a sola lettura
  2.   Private _propReadOnly As Integer
  3.   Public ReadOnly Property CountDown() As Integer
  4.     Get
  5.       _propReadOnly -= 1
  6.       Return _propReadOnly
  7.     End Get
  8.   End Property
  9.  
  10.   ' proprieta' a sola scrittura
  11.   Public WriteOnly Property NumeroCartaCredito() As Integer
  12.     Set(ByVal value As Integer)
  13.       _propReadOnly = value
  14.     End Set
  15.   End Property

Nel primo esempio illustrato la proprietà può essere letta ma non modificata, dato che un conto alla rovescia deve essere gestito solo internamente al programma. D’altro canto, nel secondo caso la proprietà può essere valorizzata ma non letta dall’esterno, visto che nessuno vorrebbe che qualcun altro fosse in grado di leggere il numero di carta di credito da noi inserito.

VB 2010: numeri complessi con il tipo Complex

Un altro tipo di nuova introduzione è il tipo System.Numerics.Complex, per rappresentare numeri complessi, cioè numeri dotati di una parte numerica reale (a virgola mobile) e una parte numerica immaginaria. I numeri complessi sono molto utilizzati in applicazioni matematiche e scientifiche e quindi l’introduzione di questo nuovo tipo di dato è estremamente importante.

Il tipo Complex si utilizza nel seguente modo:

Visual Basic
  1.     ' definizione di un tipo complesso
  2.     Dim numeroComplesso As New Complex(125.17, 18)
  3.     MessageBox.Show("Parte reale: " &
  4.       numeroComplesso.Real.ToString &
  5.       Environment.NewLine &
  6.       "Parte immaginaria: " &
  7.       numeroComplesso.Imaginary.ToString)

VB 2010: grandi numeri con il tipo BigInteger

Per certi tipi di applicazioni abbiamo sempre avuto il problema di rappresentare numeri veramente grandi: per esempio, pensate alle applicazioni di tipo matematico o scientifico oppure ad alcuni algoritmi per la sicurezza.

Con l’introduzione del nuovo tipo System.Numerics.BigInteger questo problema non esiste più. Il tipo BigInteger permette di rappresentare numeri arbitrariamente grandi (per esempio un numero di centinaia di migliaia di cifre), perché non ha un limite di dimensione superiore. L’unico limite è rappresentato dalla memoria disponibile e quindi bisogna fare attenzione a non scatenare un’eccezione OutOfMemoryException.

Dopo aver inserito nelle proprietà del progetto un riferimento al namespace System.Numerics, potete utilizzare il tipo BigInteger così:

Visual Basic
  1.     ' Dichiarazione di una variabile
  2.     ' di tipo BigInteger
  3.     Dim numeroExtraLong As New BigInteger
  4.  
  5.     ' si possono passare dei numeri di tipo
  6.     ' Double al costruttore ma poi il numero
  7.     ' viene troncato (non arrotondato)
  8.     ' per esempio:
  9.     ' 987654321987654321,555 = 987654321987654321
  10.     Dim numeroXXL As BigInteger
  11.     numeroXXL = BigInteger.Parse("98765432198765424.555")
  12.  
  13.     ' un numero di un tipo pu? essere convertito
  14.     ' in BigInteger con un operatore di conversione
  15.     Dim numConDecimali As Single = 201004.12
  16.     Dim altroNumeroXXL As BigInteger =
  17.         CType(numConDecimali, BigInteger)

VB 2010: continuazione implicita di linea

Una delle caratteristiche più amate-odiate dai programmatori VB è il carattere underscore ("_"), cioè il carattere che permette di andare a capo in una istruzione. Per esempio:

Visual Basic
  1.     Dim lungaStringaDiTesto As String = _
  2.       "Questa e' una lunga stringa di testo, " & _
  3.       "cosi' lunga che non ci sta in una sola " & _
  4.       "riga. Se voglio mantenere una buona " & _
  5.       "leggibilita' devo andare a capo spesso " & _
  6.       "e devo utilizzare l'underscore."

 

Finalmente possiamo tralasciare questo carattere e scrivere codice come questo (speriamo che prima o poi si possa tralasciare anche il carattere &):

Visual Basic
  1.     Dim lungaStringaDiTesto As String =
  2.       "Questa e' una lunga stringa di testo, " &
  3.       "cosi' lunga che non ci sta in una sola " &
  4.       "riga. Se voglio mantenere una buona " &
  5.       "leggibilita' devo andare a capo spesso " &
  6.       "e posso NON utilizzare l'underscore."

 

oppure come questo:

Visual Basic
  1.     Dim linguaggi As New List(Of String) From
  2.     {
  3.       "Visual Basic",
  4.       "C#",
  5.       "C++",
  6.       "F#"
  7.     }

 

Esistono alcune eccezioni: una di queste riguarda la parola riservata Handles, come nel seguente esempio.

Visual Basic
  1.   ' cosi' funziona:
  2.   Private Sub Form1_Load(
  3.     ByVal sender As System.Object,
  4.     ByVal e As System.EventArgs) _
  5.     Handles MyBase.Load
  6.   End Sub
  7.  
  8.   ' cosi' NON funziona:
  9.   Private Sub Form2_Load(
  10.   ByVal sender As System.Object,
  11.   ByVal e As System.EventArgs)
  12.     Handles MyBase.Load
  13.   End Sub

 

L’utilità di questa modifica diventa molto più evidente nelle query LINQ o in istruzioni LINQ to XML:

Visual Basic
  1.     ' query LINQ:
  2.     Dim query =
  3.         From proc In Process.GetProcesses.AsEnumerable()
  4.         Where (proc.ProcessName.StartsWith("SQL"))
  5.     Select proc
  6.  
  7.     ' LINQ to XML:
  8.     Dim doc =
  9.     <?xml version="1.0"?>
  10.     <Processes>
  11.       <%= From proc In query
  12.         Select
  13.         <Process>
  14.           <Name <%= proc.ProcessName %>/>
  15.         </Process>
  16.       %>
  17.     </Processes>

 

Nel primo caso c’è una forte somiglianza con una normale istruzione SQL, nel secondo caso si ottiene una leggibilità del codice senza precedenti.

VB 2010: Collection Initializers

E’ stato semplificato il modo per definire e inizializzare una collezione, inserendo gli elementi che la compongono con un’unica istruzione.

Per esempio, per inserire degli elementi all’interno di una List e di un Dictionary, prima dovevamo utilizzare tante istruzioni quanti gli elementi da inserire, ciascuna delle quali chiamava il metodo Add dell’oggetto:

 

Visual Basic
  1.     Dim miaListaSoftware As New List(Of String)
  2.     With miaListaSoftware
  3.       .Add("Visual Studio 2010")
  4.       .Add("Visual Basic 2010 Express")
  5.       .Add("Visual C# 2010 Express")
  6.       .Add("Visual Web Developer 2010 Express")
  7.       .Add("Visual C++ 2010 Express")
  8.     End With
  9.     Dim mioDizionario As New Dictionary(Of Integer, String)
  10.     mioDizionario.Add(1, "VB")
  11.     mioDizionario.Add(2, "C#")
  12.     mioDizionario.Add(3, "F#")
  13.     mioDizionario.Add(4, "C++")

 

Anche ora possiamo utilizzare questa sintassi, ma ne possiamo utilizzare anche una alternativa:

 

Visual Basic
  1.     Dim miaListaSoftware As New List(Of String) From {
  2.         "Visual Studio 2010",
  3.         "Visual Basic 2010 Express",
  4.         "Visual C# 2010 Express",
  5.         "Visual Web Developer 2010 Express",
  6.         "Visual C++ 2010 Express"}
  7.     Dim mioDizionario As New Dictionary(Of Integer, String) From
  8.         {{1, "VB"}, {2, "C#"}, {3, "F#"}, {4, "C++"}}

 

Per motivi di spazio e di leggibilità abbiamo suddiviso le istruzioni su più righe, ma avremmo potuto scrivere entrambe le istruzioni su un’unica riga.

Notate il nuovo uso della clausola From che permette di inserire un elenco di elementi racchiusi tra parentesi graffe. Nel caso della seconda istruzione, poi, trattandosi di coppie di elementi da inserire, le parentesi graffe sono nidificate.

Dietro le quinte, Visual Basic chiama ancora il metodo Add dei due oggetti, ma lo fa senza obbligarci a specificarlo in modo esplicito.

VB2010: le novità sugli array

In Visual Basic 2008 era stato introdotto un nuovo concetto: la dichiarazione di variabili per inferenza. Con il termine "inferenza" intendiamo riferirci a quella particolare tecnica che permette di definire il tipo di dato di una variabile in base al valore che le viene assegnato.

Questa tecnica aveva suscitato alcune obiezioni, in particolar modo da alcuni puristi del linguaggio VB.NET che vedevano l’introduzione dell’inferenza come un ritorno del tipo Variant di VB6.

In realtà l’inferenza è molto diversa dal tipo Variant, perché quest’ultimo poteva assumere diversi tipi di dati nel corso dell’esecuzione del programma. La definizione per inferenza, invece, permette di definire il tipo di dato delle variabili solo al momento della prima assegnazione, poi non cambia più.

Il comportamento di Visual Basic nei confronti dell’inferenza è condizionato dallo stato di una particolare opzione del progetto: Option Infer. Impostando questa opzione a On (attivo per default) si potrà abilitare l’inferenza, mentre impostandola a Off si disabiliterà completamente.

Dopo questa doverosa premessa, scopriamo la novità di Visual Basic 2010: ora anche il tipo di dato degli array può essere definito per inferenza. Questo significa che possiamo scrivere del codice come il seguente:

 

Visual Basic
  1.     ' dichiarazioni per inferenza:
  2.     ' array di tipo Integer
  3.     Dim arrInteri = {10, 20, 30, 40, 50}
  4.     ' array di tipo String
  5.     Dim arrStringhe = {"Uno", "Due", "Tre"}
  6.     ' Naturalmente nulla vieta di utilizzare ancora la precedente sintassi:
  7.     ' dichiarazione secondo la vecchia sintassi:
  8.     Dim arrInteri2() As Integer = {5, 4, 3, 2, 1}

 

Se mescoliamo elementi di tipi diversi nell’insieme di elementi passati all’array, abbiamo due possibili comportamenti: se l’opzione del progetto denominata Option Strict è impostata a On, otterremo un errore, mentre se è impostata a Off l’array sarà di tipo Object.

Naturalmente consigliamo di impostare Option Strict On, perché l’utilizzo del tipo Object non è consigliabile, perché equivale all’utilizzo di Variant in VB6 e può diventare la fonte di un errore a runtime difficilmente individuabile.

Vi consigliamo, quindi, di impostare Option Strict On in tutti i vostri progetti, per garantirvi di restare sempre nell’ambito della tipizzazione forte, evitando in questo modo tanti grattacapi.

Un’altra novità degli array è l’introduzione degli array literals che permettono di dichiarare nello stesso modo sia degli array multidimensionali, sia i jagged array (matrici irregolari o array di array).

Abbiamo già visto la sintassi degli array literals nell’esempio di definizione e inizializzazione di un dizionario, ma vediamo ulteriori esempi, non necessariamente legati a classi contenitore del Framework (se non i classici array):

 

Visual Basic
  1.     ' definisco e inizializzo un array
  2.     ' multidimensionale
  3.     Dim arrCoppie =
  4.         {{5, 3}, {4, 2}, {1, 6}}
  5.     ' jagged array (il terzo gruppo ha
  6.     ' 3 elementi)
  7.     Dim arrJagged =
  8.         {({5, 3}), ({4, 2}), ({1, 7, 6})}

 

Per accedere a un array inserito all’interno di un altro array, possiamo utilizzare una sintassi molto intuitiva:

 

Visual Basic
  1.     ' accesso agli elementi del jagged array
  2.     Dim nuovoArray = arrJagged(1)
  3.     ' leggo il terzo elemento del terzo array
  4.     Dim elemento As Integer = arrJagged(2)(2)

 

Gli indici utilizzati all’interno delle parentesi sono inferiori di una unità alla posizione dell’elemento perché, lo ricordiamo, la base degli indici, nel .NET Framework, è sempre zero (non uno).

Il nuovo riferimento per gli sviluppatori: sviluppareperwindows.it

Microsoft Italia ha lanciato il nuovo portale per gli sviluppatori "Sviluppare per Windows" (http://msdn.microsoft.com/it-it/gg649876).

Vi potete trovare tutte le risorse utili per sviluppare su qualsiasi piattaforma: Windows Desktop, Windows Azure, Windows Phone, Silverlight e molto altro.

Vi consiglio quindi di aggiungere il link sopra indicato tra i vostri preferiti e di consultare periodicamente i contenuti del portale, perché prossimamente saranno aggiunti molti materiali utili per lo sviluppo di qualsiasi tipo di applicazione abbiate in mente!

Espressioni Lambda multi-linea e Statement Lambda

Le espressioni lambda erano state introdotte già nella versione 2008 di Visual Basic, per cui non sono una novità assoluta. Tuttavia, nella versione 2010 sono state ulteriormente potenziate.

Infatti, in precedenza, nelle espressioni lambda poteva essere indicato il codice da eseguire come funzione (Function), quindi con il ritorno di un valore. Ora non è più così: nelle espressioni lambda possiamo inserire anche delle routine (Sub), senza quindi dover necessariamente richiedere un valore di ritorno.

Completa il quadro l’abolizione del carattere di continuazione di linea, come abbiamo già visto in questo articolo, permettendo così di sviluppare l’istruzione su più righe, ma mantenendo una buona leggibilità del codice. Vediamo alcuni esempi.

Innanzi tutto vediamo la sintassi che era ammessa da Visual Basic 2008 (tuttora utilizzabile):

Visual Basic
  1.     ' sintassi con VB 2008
  2.     Dim processi = _
  3.         Process.GetProcesses.Where( _
  4.         Function(proc) proc.ProcessName.StartsWith("F"))

 

Questo codice legge il nome di tutti i processi in esecuzione sul computer che iniziano con la lettera "F" e li inserisce nella variabile processi.

In Visual Basic 2010 possiamo scrivere un’istruzione molto più articolata:

Visual Basic
  1.     ' sintassi con VB 2010
  2.     Dim processi = Process.GetProcesses.Where(
  3.     Function(p)
  4.       Try
  5.         Return p.ProcessName.
  6.                 StartsWith("F")
  7.       Catch ex As Win32Exception
  8.         ' qui si inserisce la gestione
  9.         ' dell'eccezione
  10.         Return False
  11.       End Try
  12.     End Function)

 

Come potete vedere, non solo l’istruzione si sviluppa in più righe senza l’uso del carattere di continuazione, ma addirittura è possibile inserire al suo interno un blocco TryCatchEnd Try come in un qualsiasi metodo classico.

L’ultima cosa che dobbiamo ancora vedere è come leggere le stringhe inserite nella variabile processi. Possiamo farlo in due modi, con il metodo classico o con una Statement Lambda:

Visual Basic
  1.     ' scorrimento classico dell'elenco
  2.     processi.ToList.ForEach(Sub(proc) MessageBox.Show(proc.ProcessName))

 

Con questa istruzione, ad ogni ciclo viene visualizzato un messaggio sullo schermo con il nome del processo.

Nella nuova sintassi, anche questa volta possiamo sviluppare l’istruzione su più righe, con un blocco di istruzioni e con una leggibilità che finora non era mai stata possibile (ElencoProcessi è un controllo di tipo TextBox):

Visual Basic
  1.     ' statement lambda per lo scorrimento
  2.     ' degli elementi
  3.     processi.ToList.ForEach(
  4.     Sub(proc)
  5.       Form1.ElencoProcessi.Text &= "Nome: "
  6.       Form1.ElencoProcessi.Text &= proc.ProcessName
  7.       Form1.ElencoProcessi.Text &= System.Environment.NewLine
  8.     End Sub)

System.Tuple

Un oggetto di tipo System.Tuple è un oggetto che permette di raggruppare in un’unica struttura più elementi, ciascuno con il proprio tipo di dato.

Ecco un paio di esempi d’uso di questo oggetto:

 

Code Snippet
  1.    Dim t1 As System.Tuple(Of String, Integer) =
  2.      Tuple.Create("Mario", 46)
  3.     MessageBox.Show(t1.Item1 & " " & t1.Item2)
  4.  
  5.     Dim t2 As Tuple(Of String, String, Date) =
  6.       tuple.Create("io", "Programmo", #5/15/2010#)
  7.     MessageBox.Show(t2.Item1 & t2.Item2 & " " & t2.Item3)

Il risultato ottenuto nei due casi sarà il seguente:

    Mario 46

    ioProgrammo 15/05/2010

 

E’ possibile anche sostituire un parametro con un altro oggetto Tuple, utilizzando anche il metodo statico Create per non dover utilizzare il costruttore:

 

Code Snippet
  1. Dim t3 = Tuple.Create(
  2.       "io", "Programmo", Tuple.Create("Maggio", 2010))
  3.     MessageBox.Show(t3.Item1 & t3.Item2 & " " &
  4.       t3.Item3.Item1 & " " & t3.Item3.Item2)

 

Il risultato di quest’ultimo esempio è il seguente:

    ioProgrammo Maggio 2010

Questo è anche un ottimo stratagemma per poter superare il limite di 8 parametri ammessi dal costruttore.

VB 2010 – Covarianza e Controvarianza

Spiegare i concetti relativi alla varianza generica non è semplicissimo, soprattutto con l’uso di termini come Covarianza e di Controvarianza, e presuppone una conoscenza abbastanza approfondita della programmazione orientata agli oggetti, ma ci proveremo con qualche esempio.

Covarianza e Controvarianza sono, appunto, due aspetti distinti e complementari della Varianza generica, nell’ambito dell’ereditarietà in una gerarchia di classi.

Iniziamo con la Covarianza: supponiamo di avere un oggetto di tipo Insalata e un oggetto di tipo Carota e di voler assegnare questi oggetti a un oggetto di tipo Verdura. Per la programmazione orientata agli oggetti questo dovrebbe essere possibile, visto che Insalata e Carota sono classi che derivano dalla classe Verdura. Tuttavia, fino alla versione 2008 di Visual Basic, questo non era possibile perché era necessario effettuare una conversione esplicita.

In Visual Basic 2010, otteniamo il risultato desiderato dalle classi derivate Insalata e Carota, ma nell’ambito di una collezione di oggetti di tipo astratto Verdura. Questo risultato lo possiamo ottenere solamente utilizzando un’interfaccia IEnumerable(Of Object), dove Object in questo caso viene sostituito dal tipo Verdura.

Vediamo un esempio più semplice con una lista di stringhe:

 

Code Snippet
  1.     ' definisce una lista di stringhe
  2.     Dim listaStringhe As New List(Of String) From
  3.            {
  4.              "Visual Studio ",
  5.              "2010 ",
  6.              "su ",
  7.              "io ",
  8.              "Programmo"
  9.            }
  10.     ' definisce un insieme generico di elementi
  11.     Dim lstCovarianza As IEnumerable(Of Object) =
  12.           listaStringhe
  13.     ' inizializza un oggetto di tipo StringBuilder
  14.     ' per il concatenamento dinamico delle stringhe
  15.     Dim sb As New StringBuilder
  16.     ' ciclo per leggere tutte le stringhe
  17.     ' dall'insieme generico
  18.     For Each lst In lstCovarianza
  19.       ' accoda la prossima stringa letta
  20.       sb.Append(lst)
  21.     Next
  22.     ' visualizza il risultato
  23.     MessageBox.Show(sb.ToString)

 

Nella Controvarianza, il concetto è diametralmente opposto: da una classe derivata Insalata o Carota, ricaviamo il risultato desiderato sfruttando la classe astratta Verdura.

Come nella Covarianza dobbiamo necessariamente utilizzare un’interfaccia IEnumerable, nella Controvarianza utilizziamo i delegati.

Come esempio classico di Controvarianza possiamo citare un metodo per gestire due eventi distinti di un controllo visuale: per esempio gli eventi MouseClick, cioè il normale click con il tasto sinistro del mouse, e KeyUp che avviene al momento del rilascio di un tasto.

Normalmente, questi due eventi ricevono due oggetti diversi: il primo riceve un oggetto di tipo MouseEventArgs, mentre il secondo riceve un oggetto di tipo KeyEventArgs. Si porrebbe, quindi, il problema di gestire questi due diversi tipi di oggetto. Per fortuna, entrambi sono derivati da System.EventArgs ed ereditano quindi tutte le caratteristiche principali da quest’ultimo.

In Visual Basic 2008 possiamo scrivere qualcosa di simile a questo codice:

 

Code Snippet
  1.   ' definisco un metodo comune
  2.   ' per i due diversi eventi
  3.   Private Sub GestoreComune(
  4.             ByVal sender As Object,
  5.             ByVal e As EventArgs)
  6.     ' visualizza un messaggio
  7.     MessageBox.Show("Click o tasto!")
  8.   End Sub
  9.  
  10.   ' questo ? il normale metodo gestore
  11.   ' dell'evento Load di un form
  12.   Private Sub frmMain_Load(
  13.         ByVal sender As System.Object,
  14.         ByVal e As System.EventArgs) _
  15.         Handles MyBase.Load
  16.     AddHandler btnTest.MouseClick,
  17.       AddressOf GestoreComune
  18.     AddHandler btnTest.KeyUp,
  19.       AddressOf GestoreComune
  20.   End Sub

 

 

In Visual Basic 2010 possiamo anche scrivere nella seguente forma alternativa:

 

Code Snippet
  1.   ' funziona solo in VB 2010:
  2.     AddHandler btnMessaggi.KeyUp,
  3.       Sub() MessageBox.Show("Evento KeyUp")
  4.  
  5.     AddHandler btnMessaggi.Click,
  6.       Sub()
  7.         Dim msg As String
  8.         msg = "Evento Click"
  9.         MessageBox.Show(msg)
  10.       End Sub

 

In questo esempio ridefiniamo gli eventi KeyUp e Click, in modo tale che se si verifica il primo evento viene visualizzato "Evento KeyUp", mentre se si verifica il secondo viene visualizzato "Evento Click".

Provate l’esempio e vedrete che le situazioni che potrete incontrare sono diverse. Per esempio, se portate il focus sul pulsante btnMessaggi e premete la barra degli spazi, vedrete apparire in sequenza entrambi i messaggi: questo avviene perché la pressione della barra degli spazi equivale a un click del mouse e quindi scatena l’evento Click, ma scatena anche l’evento KeyUp al momento del sollevamento del tasto. Se fate click con il mouse, vedrete il messaggio "Evento Click", mentre se premete qualsiasi altro tasto diverso dalla barra, vedrete il messaggio "Evento KeyUp".