Oppure

Loading
Il Framework .NET è in grado di eseguire conversioni automatiche a runtime verso tipi di ampiezza maggiore, per esempio è in grado di convertire Int16 in Int32, Char in String, Single in Double e via dicendo. Queste operazioni di conversione vengono dette widening (dall'inglese wide = largo), ossia che avvengono senza la perdita di dati, poiché trasportano un valore che contiene una data informazione in un tipo che può contenere più informazioni. Gli operatori di conversione servono per eseguire conversioni che vanno nella direzione opposta, e che sono quindi, narrowing (dall'inglese narrow = stretto). Queste ultime possono comportare la perdita di dati e perciò generano un errore se implicite.


CType

CType è l'operatore di conversione universale e permette la conversione di qualsiasi tipo in qualsiasi altro tipo, almeno quando questa è possibile. La sintassi è molto semplice:
[Variabile] = CType([Valore da convertire], [Tipo in cui convertire]) 
Ad esempio:
Dim I As Int32 = 50
'Converte I in un valore Byte
Dim B As Byte = CType(I, Byte) 
Questa lista riporta alcuni casi in cui è bene usare esplicitamente l'operatore di conversione CType:
  • Per convertire un valore intero o decimale in un valore booleano;
  • Per convertire un valore Single o Double in Decimal;
  • Per convertire un valore intero con segno in uno senza segno;
  • Per convertire un valore intero senza segno in uno con segno della stessa ampiezza (ad esempio da UInt32 a Int32).
Oltre a CType, esistono moltissime versioni più corte di quest'ultimo che convertono in un solo tipo: CInt converte sempre in Int32, CBool sempre in booleano, CByte in byte, CShort Int16, CLong, CUShort, CULong, CUInt, CSng, CDbl, CDec, CStr, CDate, CObj. È inopportuno utilizzare CStr poichè ci si può sevire della funzione ToString ereditata da ogni classe da System.Object; allo stesso modo, è meglio evitare CDate, a favore di Date.Parse, come si vedrà nella lezione "DateTimePicker: Lavorare con le date".
CType può comunque essere usato per qualsiasi altra conversione contemplabile, anche e soprattutto con i tipi Reference.


DirectCast

DirectCast lavora in un modo leggermente di diverso: CType tenta sempre di convertire l'argomento di orgine nel tipo specificato, mentre DirectCast lo fa solo se tale valore può essere sottoposto al casting (al "passaggio" da un tipo all'altro, piuttosto che alla conversione) verso il tipo indicato. Perciò non è, ad esempio, in grado di convertire una stringa in intero, e neanche un valore short in un integer, sebbene questa sia una conversione di espansione. Questi ultimi esempi non sono validi anche perchè questo particolare operatore può accettare come argomenti solo oggetti, e quindi tipi Reference. In generale, quindi, dato il leggero risparmio di tempo di DirectCast in confronto a CType, è conveniente usare DirectCast:
  • Per eseguire l'unboxing di tipi value;
  • Per eseguire il casting di una classe base in una classe derivata (vedi "Ereditarieta'");
  • Per eseguire il casting di un oggetto in qualsiasi altro tipo reference;
  • Per eseguire il casting di un oggetto in un'interfaccia.
N.B.: notare che tutti i casi sopra menzionati hanno come tipo di partenza un oggetto, proprio come detto precedentemente.


TryCast

TryCast ha la stessa sintassi di DirectCast, e quindi anche di CType, ma nasconde un piccolo pregio. Spesso, quando si esegue una conversione si deve prima controllare che la variabile in questione sia di un determinato tipo base o implementi una determinata interfaccia e solo successivamente si esegue la conversione vera e propria. Con ciò si controlla due volte la stessa variabile, prima con l'If e poi con DirectCast. TryCast, invece, permette di eseguire il tutto in un unico passaggio e restituisce semplicemente Nothing se il cast fallisce. Questo approccio rende tale operatore circa 0,2 volte più veloce di DirectCast.


Convert

Esiste, poi, una classe statica definita del namespace System - il namespace più importante di tutto il Framework. Questa classe, essendo statica (e qui facciamo un po' di ripasso), espone solo metodi statici e non può essere istanziata (non espone costruttori e comunque sarebbe inutile farlo). Essa contiene molte funzioni per eseguire la conversione verso i tipi di base ed espone anche un importante valore che vedremo molto più in là parlando dei database. Essenzialmente, tutti i suoi metodi hanno un nome del tipo "ToXXXX", dove XXXX è uno qualsiasi tra i tipi base: ad esempio, c'è, ToInt32, ToDouble, ToByte, ToString, eccetera... Un esempio:
Dim I As Int32  = 34
Dim D As Double = Convert.ToDouble(I)
' D = 34.0
Dim S As String = Convert.ToString(D)
' S = "34"
Dim N As Single = Convert.ToSingle(S)
' N = 34.0
Dim K As String = "31/12/2008"
Dim A As Date = Convert.ToDate(K)
All'interno di Convert sono definiti anche alcuni metodi per convertire una stringa da e verso il formato Base64, una particolare codifica che utilizza solo 64 caratteri, al contrario dell'ASCII standard che ne utilizza 128 o di quello esteso che ne utilizza 256. Tale codifica viene usata ad esempio nell'invio delle e-mail e produce output un terzo più voluminosi degli input, ma in compenso tutti i caratteri contemplati sono sempre leggibili (non ci sono, quindi, caratteri "speciali"). Per approfondire l'argomento, cliccate su wikipedia.
Per riprendere il discorso conversioni, sarebbe lecito pensare che la definizione di una classe del genere, quando esistono già altri operatori come CType e DirectCast - altrettanto qualificati e performanti - sia abbastanza ridondante. Più o meno è così. Utilizzare la classe Convert al posto degli altri operatori di casting non garantisce alcun vantaggio di sorta, e può anche essere ricondotta ad una questione di gusti (io personalmente preferisco CType). Ad ogni modo, c'è da dire un'altra cosa al riguardo: i metodi di Convert sono piuttosto rigorosi e forniscono dei servizi molto mirati. Per questo motivo, in casi molto vantaggiosi, ossia quando il cast può essere ottimizzato, essi eseguono pur sempre le stesse istruzioni: al contrario, CType può "ingegnarsi" e fornire una conversione più efficiente. Quest'ultimo, quindi, è leggermente più elastico ed adattabile alle situazioni.


Parse

Un'operazione di parsing legge una stringa, la elabora, e la converte in un valore di altro tipo. Abbiamo già visto un utilizzo di Parse nell'uso delle date, poiché il tipo Date espone il metodo Parse, che ci permette di convertire la rappresentazione testuale di una data in un valore date appropriato. Quasi tutti i tipi base del Framework espongono un metodo Parse, che permette di passare da una stringa a quel tipo: possiamo dire che Parse è l'inversa di ToString. Ad esempio:
Dim I As Int32 

I = Int32.Parse("27")
' I = 27

I = Int32.Parse("78.000")
' Errore di conversione!

I = Int32.Parse("123,67")
' Errore di conversione!
Come vedete, Parse ha pur sempre dei limiti: ad esempio non contempla i punti e le virgole, sebbene la conversione, vista da noi "umani", sia del tutto lecita (78.000 è settantottomila con il separatore delle migliaia e 123,67 è un numero decimale, quindi convertibile in intero con un arrotondamento). Inoltre, Parse viene anche automaticamente chiamato dai metodi di Convert quando il valore passato è una stringa. Ad esempio, Convert.ToInt32("27") richiama a sua volta Int32.Parse("27"). Per farvi vedere in che modo CType è più flessibile, ripetiamo l'esperimento di prima usando appunto CType:
Dim I As Int32 

I = CType("27", Int32)
' I = 27

I = CType("78.000", Int32)
' I = 78000

I = CType("123,67", Int32)
' I = 124
Perfetto: niente errori di conversione e tutto come ci si aspettava!


TryParse

Una variante di Parse è TryParse, anch'essa definita da molti tipi base. La sostanziale differenza risiede nel fatto che, mentre la prima può generare errori nel caso la stringa non possa essere convertita, la seconda non lo fa, ma non restituisce neppure il risultato. Infatti, TryParse accetta due argomenti, come nella seguente signature:
TryParse(ByVal s As String, ByRef result As [Tipo]) As Boolean
Dove [Tipo] dipende da quale tipo base la stiamo richiamando: Int32.TryParse avrà il secondo argomento di tipo Int32, Date.TryParse ce l'avrà di tipo Date, e così via. In sostanza TryParse tenta di eseguire la funzione Parse sulla stringa s: se ci riesce, restituisce True e pone il risultato in result (notare che il parametro è passato per indirizzo); se non ci riesce, restituisce False. Ecco un esempio:
Dim S As String = "56/0/1000"
'S contiene una data non valida
Dim D As Date

If Date.TryParse(S, D) Then
    Console.WriteLine(D.ToLongDateString())
Else
    Console.WriteLine("Data non valida!")
End If


TypeOf

TypeOf serve per controllare se una variabile è di un certo tipo, deriva da un certo tipo o implementa una certa interfaccia, ad esempio:
Dim I As Int32
If TypeOf I Is Int32 Then
  'Questo blocco viene eseguito poichè I è di tipo Int32
End If 
Oppure:
Dim T As Student
If TypeOf T Is Person Then
    'Questo blocco viene eseguito perchè T, essendo Student, è
    'anche di tipo Person, in quanto Student è una sua classe
    'derivata
End If
Ed infine un esempio sulle interfacce, che potrete tornare a guardare da qui a qualche capitolo:
Dim K(9) As Int32
If TypeOf Is IEnumerable Then
    'Questo blocco viene eseguito poiché gli array implementano
    'sempre l'interfaccia IEnumerable
End If


A cura di: Il Totem