Casting und Typkonvertierung sind zwei verschiedene Wege, einen Ausdruck von einem Datentyp in einen anderen umzuwandeln.
Die C#-Dokumentation ordnet die Typkonvertierung der Verwendung des as-Operators oder des is-Operators zu. Casting ist als Verwendung des Cast-Operators definiert.
In C# musst du sehr oft, außerhalb der Welt der numerischen Werte und Klassenhierarchien, eine Konvertierung durchführen: entweder rufst du ein Mitglied des „Ziel“-Typs auf, etwa Int32.Parse(), das einen String in eine Ganzzahl umwandelt, oder ein Mitglied des „Quell“-Typs, z. B. object.ToString(). Darauf sollten JavaScript-Entwickler und Entwickler anderer dynamischer Sprachen gefasst sein.
Beachte, dass implizite und explizite Cast-Operatoren (besprochen in operator-overloading) verfügbar sind, mit denen du recht beliebiges Casting in deine eigenen Typen bringen kannst.
C#s Typsystem ist etwas strenger als das von C oder JavaScript, und daher sind Casting-Operationen stärker eingeschränkt. Implizites Casting findet zwischen zwei numerischen Typen statt, solange der „Ziel“-Typ die Größenordnung und das Vorzeichen des Werts des „Quell“-Typs erhalten kann. Beachte in der Dokumentation die Ausnahme bei der Umwandlung in reelle Zahlen, bei der Genauigkeit verloren gehen kann.
Ein impliziter Cast wird durch keine besondere Syntax gekennzeichnet. Zum Beispiel:
int myInt = 1729;
long myLong = myInt;
Es gibt keine implizite Konvertierung eines numerischen (oder String-)Ausdrucks in bool. Die Base Class Library (BCL) stellt für diesen Zweck Convert.ToBoolean() bereit.
Ein Ausdruck vom Typ char kann implizit in int umgewandelt werden. Der Cast in die entgegengesetzte Richtung muss explizit sein. Nicht alle Werte von int sind gültige UTF-16-Zeichen.
Wo numerische Typen nicht implizit umgewandelt werden können, kannst du im Allgemeinen den expliziten Cast-Operator verwenden.
Wenn der umzuwandelnde Wert vom „Ziel“-Typ nicht dargestellt werden kann, weil dieser nicht breit genug ist oder es einen Vorzeichenkonflikt gibt, dann kann bei Ganzzahlen eine Überlaufausnahme ausgelöst werden, oder die Variable des „Ziel“-Typs kann bei Gleitkommazahlen den Wert Infinity annehmen.
Ein Ausdruck vom Typ int kann explizit in char umgewandelt werden. Das kann ein ungültiges char ergeben.
int largeInt = Int32.MaxValue;
int largeNegInt = Int32.MinValue;
ushort shortUnsignedInt = ushort.MaxValue;
float largeFloat = float.MaxValue;
float smallFloat = 17.29f;
// implicit cast
int from_ushort = shortUnsignedInt; // 65535
float from_int = largeInt; // -21474836E+09
int from_char = 'a'; // 96
// explicit cast
uint from_largeInt = (uint)largeInt; // 2147483647
uint from_neg = (uint) largeNegInt; // 2147483648 or OverflowException is thrown (if checked)
int from_smallFloat = (int) smallFloat; // 17
int from_largeFloat = (int) largeFloat; // -2147483648 or OverflowException is thrown (if checked)
char from_intc = (char) 32; // ' '
char from_invalid_int = (char) 0xdcbf; // invalid char - no exception thrown
// no cast available
int fromString = Int32.Parse("42"); // 42
string toString = largeInt.ToString(); // "2147483647"
int fromString_bad = Int32.Parse("forty two"); // FormatException is thrown
Schau dir diesen Artikel zum Schlüsselwort checked an.
Jeder Typ kann implizit in seine Basisklasse oder sein Interface konvertiert werden.
IList<int> ll = new List<int>();
Mit einem Cast-Operator kann von einer Basisklasse in eine abgeleitete Klasse konvertiert werden.
IList<int> ll = new List<int>();
List<int> l = (List<int>)ll;
Wenn der Cast fehlschlägt, weil der Typ des umgewandelten Ausdrucks nicht mit dem Typ verwandt ist, in den er umgewandelt wird, wird eine Instanz von InvalidCastException ausgelöst.
Ein üblicherer Ansatz für diese Typkonvertierungen ist die Verwendung des is-Schlüsselworts:
interface IFoo { int Bar(); }
class Foo : IFoo { public int Bar() { return 42; }}
Object r = new Random();
IFoo ifoo = new Foo();
Object o = new Foo();
int result = 1729;
if (ifoo is Foo foo)
{
result = foo.Bar();
}
// result == 42
result = 1729;
if (o is Foo foo2)
{
result = foo2.Bar();
}
// result == 42
result = 1729;
if (r is Foo foo3)
{
result = foo3.Bar();
}
// result == 1729
Das as-Schlüsselwort erfüllt eine ähnliche Funktion wie is, z. B. var foo = ifoo as Foo;. In diesem Beispiel ist foo null, wenn ifoo nicht vom Typ Foo ist; andernfalls wird ifoo ihm zugewiesen.
Typen können ihre eigenen benutzerdefinierten expliziten und impliziten Cast-Operatoren definieren.
Beispiele für explizite und implizite Casts in der BCL sind Konvertierungen vom BigInteger-Struct in andere numerische Typen und zurück.
typeof
Wenn du den genauen Typ eines Objekts ermitteln musst, ist is möglicherweise etwas zu großzügig, da es ein Objekt in eine Klasse oder eine ihrer Basisklassen umwandelt. typeof und Object.GetType() sind in diesem Fall die Lösung.
object o = new List<int>();
o is ICollection<int> // true
o.GetType() == typeof(ICollection<int>) // false
o is List<int> // true
o.GetType() == typeof(List<int>) // true