Ricerca…
Osservazioni
La trasmissione non è la stessa cosa di Conversione . È possibile convertire il valore di stringa "-1"
in un valore intero ( -1
), ma ciò deve essere eseguito tramite metodi di libreria come Convert.ToInt32()
o Int32.Parse()
. Non può essere fatto usando direttamente la sintassi del cast.
Trasmetti un oggetto a un tipo di base
Date le seguenti definizioni:
public interface IMyInterface1
{
string GetName();
}
public interface IMyInterface2
{
string GetName();
}
public class MyClass : IMyInterface1, IMyInterface2
{
string IMyInterface1.GetName()
{
return "IMyInterface1";
}
string IMyInterface2.GetName()
{
return "IMyInterface2";
}
}
Trasmettere un oggetto ad un esempio di tipo base:
MyClass obj = new MyClass();
IMyInterface1 myClass1 = (IMyInterface1)obj;
IMyInterface2 myClass2 = (IMyInterface2)obj;
Console.WriteLine("I am : {0}", myClass1.GetName());
Console.WriteLine("I am : {0}", myClass2.GetName());
// Outputs :
// I am : IMyInterface1
// I am : IMyInterface2
Casting esplicito
Se si sa che un valore è di un tipo specifico, è possibile eseguirlo esplicitamente su quel tipo per poterlo utilizzare in un contesto in cui è necessario quel tipo.
object value = -1;
int number = (int) value;
Console.WriteLine(Math.Abs(number));
Se provassimo a passare il value
direttamente a Math.Abs()
, avremmo ottenuto un'eccezione in fase di compilazione perché Math.Abs()
non ha un sovraccarico che accetta un object
come parametro.
Se non è possibile eseguire il cast di un value
su un int
, la seconda riga in questo esempio genera una InvalidCastException
Safe Explicit Casting (operatore `as`)
Se non sei sicuro che un valore sia del tipo che pensi di essere, puoi lanciarlo in sicurezza usando l'operatore as
. Se il valore non è di quel tipo, il valore risultante sarà null
.
object value = "-1";
int? number = value as int?;
if(number != null)
{
Console.WriteLine(Math.Abs(number.Value));
}
Si noti che null
valori null
non hanno alcun tipo, quindi la parola chiave as
renderà sicuramente null
quando si esegue il cast di qualsiasi valore null
.
Casting implicito
Un valore verrà automaticamente convertito nel tipo appropriato se il compilatore sa che può sempre essere convertito in quel tipo.
int number = -1;
object value = number;
Console.WriteLine(value);
In questo esempio, non è stato necessario utilizzare la tipica sintassi di trasmissione esplicita perché il compilatore sa che tutti gli int
possono essere trasmessi agli object
s. In effetti, potremmo evitare di creare variabili e passare -1
direttamente come argomento di Console.WriteLine()
che si aspetta un object
.
Console.WriteLine(-1);
Controllo della compatibilità senza casting
Se è necessario sapere se il tipo di un valore estende o implementa un determinato tipo, ma non si desidera eseguire effettivamente il cast come quel tipo, è possibile utilizzare l'operatore is
.
if(value is int)
{
Console.WriteLine(value + "is an int");
}
Conversioni numeriche esplicite
Gli operatori di casting espliciti possono essere utilizzati per eseguire conversioni di tipi numerici, anche se non si estendono o si implementano a vicenda.
double value = -1.1;
int number = (int) value;
Si noti che nei casi in cui il tipo di destinazione ha meno precisione rispetto al tipo originale, la precisione andrà persa. Ad esempio, -1.1
come valore doppio nell'esempio precedente diventa -1
come valore intero.
Inoltre, le conversioni numeriche si basano sui tipi in fase di compilazione, quindi non funzioneranno se i tipi numerici sono stati "incapsulati" in oggetti.
object value = -1.1;
int number = (int) value; // throws InvalidCastException
Operatori di conversione
In C #, i tipi possono definire operatori di conversione personalizzati, che consentono di convertire i valori in e da altri tipi utilizzando cast espliciti o impliciti. Ad esempio, considera una classe che intende rappresentare un'espressione JavaScript:
public class JsExpression
{
private readonly string expression;
public JsExpression(string rawExpression)
{
this.expression = rawExpression;
}
public override string ToString()
{
return this.expression;
}
public JsExpression IsEqualTo(JsExpression other)
{
return new JsExpression("(" + this + " == " + other + ")");
}
}
Se volessimo creare un JsExpression che rappresenti un confronto tra due valori JavaScript, potremmo fare qualcosa del genere:
JsExpression intExpression = new JsExpression("-1");
JsExpression doubleExpression = new JsExpression("-1.0");
Console.WriteLine(intExpression.IsEqualTo(doubleExpression)); // (-1 == -1.0)
Ma possiamo aggiungere alcuni operatori di conversione espliciti a JsExpression
, per consentire una conversione semplice quando si utilizza il cast esplicito.
public static explicit operator JsExpression(int value)
{
return new JsExpression(value.ToString());
}
public static explicit operator JsExpression(double value)
{
return new JsExpression(value.ToString());
}
// Usage:
JsExpression intExpression = (JsExpression)(-1);
JsExpression doubleExpression = (JsExpression)(-1.0);
Console.WriteLine(intExpression.IsEqualTo(doubleExpression)); // (-1 == -1.0)
Oppure, potremmo cambiare questi operatori in implicito per rendere la sintassi molto più semplice.
public static implicit operator JsExpression(int value)
{
return new JsExpression(value.ToString());
}
public static implicit operator JsExpression(double value)
{
return new JsExpression(value.ToString());
}
// Usage:
JsExpression intExpression = -1;
Console.WriteLine(intExpression.IsEqualTo(-1.0)); // (-1 == -1.0)
Operazioni di fusione LINQ
Supponiamo di avere tipi come il seguente:
interface IThing { }
class Thing : IThing { }
LINQ consente di creare una proiezione che modifica il tipo generico in fase di compilazione di un oggetto IEnumerable<>
tramite i metodi di estensione Enumerable.Cast<>()
ed Enumerable.OfType<>()
.
IEnumerable<IThing> things = new IThing[] {new Thing()};
IEnumerable<Thing> things2 = things.Cast<Thing>();
IEnumerable<Thing> things3 = things.OfType<Thing>();
Quando viene valutato things2
, il metodo Cast<>()
proverà a things2
tutti i valori nelle things
in Thing
s. Se incontra un valore che non può essere lanciato, verrà lanciata una InvalidCastException
.
Quando viene valutato things3
, il OfType<>()
farà lo stesso, eccetto che se incontra un valore che non può essere lanciato, semplicemente ometterà quel valore anziché lanciare un'eccezione.
A causa del tipo generico di questi metodi, non possono richiamare operatori di conversione o eseguire conversioni numeriche.
double[] doubles = new[]{1,2,3}.Cast<double>().ToArray(); // Throws InvalidCastException
Puoi semplicemente eseguire un cast all'interno di .Select()
come soluzione alternativa:
double[] doubles = new[]{1,2,3}.Select(i => (double)i).ToArray();