| 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 |