Casting | ||
Differenze tra Value e Reference Type |
Così come il boxing e l'unboxing permettono la conversione da value type a reference type e viceversa, la conversione tra reference type (oggetti) di tipi diversi è attuata attraverso il casting. In conformità con l'architettura del .NET Framework l'operazione in C# è completamente type safe, e questo implica un vantaggio non indifferente, dal momento che in un ambiente unmanaged come C++ può avere, in caso di errori, effetti devastanti. Dal momento che la sicurezza sui tipi è una delle principali caratteristiche del CLR, esso è sempre a conoscenza di che tipo è un qualunque oggetto. Anche il programmatore può sempre scoprire l'esatto tipo di un oggetto chiamando il metodo GetType. Dal momento che questo metodo non è virtuale, un tipo non può mai "imbrogliare", ad esempio scavalcando il metodo GetType per dichiararsi di tipo diverso da quello di appartenenza. Per un programmatore è spesso necessario eseguire il cast (conversione) di un oggetto da un tipo all'altro e C# non richiede nessuna sintassi speciale per farlo con i propri tipi base. Comunque C# richiede che lo sviluppatore converta esplicitamente un tipo in uno dei suoi tipi derivati. Supponiamo di creare due classi, mela (apple) e arancia (orange) e tentare di convertire mele in arance, operazione che C# (e la natura, per ora.) non ci permetterà di fare. using System; public class App { class apple { public string Fruit() { return "Apple"; } } class orange { public string Fruit() { return "Orange"; } } static void Main() { apple myApple = new apple(); orange myOrange = new orange(); Console.WriteLine(myApple.Fruit()); Console.WriteLine(myOrange.Fruit()); } } Casting Anche se si andrà in contro ad una sconfitta, tentiamo comunque la conversione: static void Main() { apple myApple = new apple(); orange anotherOrange = (orange)myApple; Console.WriteLine(myApple.Fruit()); Console.WriteLine(anotherOrange.Fruit()); } Con questo codice l'unica cosa che si ottiene è il blocco della compilazione. C# sa che la conversione non è valida e l'eseguibile non sarà generato. La ragione è ovviamente legata al fatto che la classe apple non ha nulla in comune con la classe orange. In questo caso si utilizza un approccio diverso: per prima cosa si inserisce uno dei tipi in un oggetto generico objGeneral ed in seguito lo si converte nel tipo appropriato: static void Main() { apple myApple = new apple(); object objGeneral = myApple; orange anotherOrange = (orange)objGeneral; Console.WriteLine(myApple.Fruit()); Console.WriteLine(anotherOrange.Fruit()); } Quando si sceglie un tipo sbagliato come è stato appositamente fatto qui, il CLR solleva una eccezione del tipo InvalidCastException durante il runtime. Per catturare l'errore [vedi pagina sulle exception]: static void Main() { apple myApple = new apple(); object objGeneral = myApple; try { orange anotherOrange = (orange)objGeneral; // fai quel che vuoi con l'arancia! } catch(InvalidCastException e) { Console.WriteLine("L'arancia è marcia: "+e); } } In questo modo però si è venuti a conoscenza dell'insuccesso del cast solo attraverso un'eccezione. Sarebbe meglio poter sapere prima se un cast andrà a buon fine oppure no. E' qui che entra in gioco l'operatore is. L'operatore is Come annunciato questo operatore permette di chiedere se il cast avrà successo o farà sorgere un'eccezione. Il codice seguente mostra come utilizzarlo in una applicazione. static void Main() { apple myApple = new apple(); object objGeneral = myApple; if (objGeneral is orange) { orange anotherOrange = (orange)objGeneral; // fai quel che vuoi con l'arancia! } else { Console.WriteLine("Non è un'Arancia!"); } } L'operatore as L'operatore as potrebbe essere considerato un cast senza eccezioni. La conversione è portata avanti in silenzio e se questa dovesse fallire, la variabile destinazione sarebbe impostata al valore null. Tutto ciò che rimane da fare è controllarla con uno statement if: static void Main() { apple myApple = new apple(); object objGeneral = myApple; orange anotherOrange; anotherOrange = objGeneral as orange; if (null != anotherOrange) { // fai quel che vuoi con l'arancia! } else { Console.WriteLine("Una bella spremuta di mela no?"); } } Fonti: http://www.aspheute.com/english/20001019.asp Documentazione .NET Framework SDK |