C# wandelt nie von selbst zwischen nicht verwandten Typen um. Ein String mit Ziffern bleibt ein String, und ein double wird nicht stillschweigend zu einem int. Du wandelst explizit um, und welches Werkzeug du nimmst, hängt davon ab, was du umwandelst: Text in eine Zahl (Parsen), einen numerischen Typ in einen anderen (Casten) oder ein Objekt in einen spezifischeren Typ (as, is).
String in int: Parse, TryParse und Convert
Es gibt drei Standardwege, Text in ein int zu verwandeln:
Ausgabe:
2500
TryParse ok: 1250
TryParse failed, d = 0
42
-17
int.TryParse gibt ein bool zurück und schreibt das Ergebnis in eine out-Variable, die bei einem Fehlschlag auf 0 gesetzt wird. Weil fehlerhafte Eingaben bei allem, was ein Benutzer tippt, normal sind, ist TryParse die Standardwahl für Eingaben, Dateien und Query-Strings. Dieselben Methoden gibt es für jeden numerischen Typ: long.TryParse, double.TryParse, decimal.Parse und so weiter.
Was jede Methode mit fehlerhafter Eingabe macht
Die drei Methoden unterscheiden sich nur darin, wie sie scheitern:
Ausgabe:
int.Parse(null) throws ArgumentNullException
Convert.ToInt32(null) = 0
int.Parse("abc") throws FormatException
int.Parse("12.5") throws FormatException
int.Parse("1,000") throws FormatException
int.Parse("9999999999") throws OverflowException
int.Parse("") throws FormatException
Eine FormatException trägt die bekannte Meldung „Input string was not in a correct format“ (ab .NET 8 „The input string '12.5' was not in a correct format“, mit zitiertem Text) und ist einer der häufigsten Laufzeitfehler in C#: "12.5" ist kein int, und "1,000" auch nicht. Um solche Werte zu akzeptieren, parse als decimal oder sag dem Parser, welche Stile erlaubt sind:
Ausgabe:
1000
255
13
10
Kultur: warum aus "1.5" 15 werden kann
Beim Parsen wird standardmäßig die aktuelle Kultur verwendet, und Kulturen sind sich bei Trennzeichen uneinig. Im Deutschen und in einigen anderen europäischen Kulturen ist das Dezimaltrennzeichen ein Komma, und der Punkt gruppiert Tausender. Derselbe String ergibt verschiedene Zahlen:
Ausgabe:
1.5
15
1.5
Code, der Datendateien, JSON, Konfiguration oder sonst etwas Maschinengeneriertes liest, sollte immer CultureInfo.InvariantCulture übergeben, sowohl beim Parsen als auch beim Formatieren. Sonst funktioniert dasselbe Programm auf dem Rechner eines Entwicklers und liest auf einem Server mit anderer Spracheinstellung jede Zahl falsch. Nimm die aktuelle Kultur nur für Text, den ein Mensch getippt hat oder lesen wird.
Implizite und explizite numerische Umwandlungen
Erweiternde Umwandlungen geschehen implizit: int in long, int in double, float in double, int in decimal. Eine Umwandlung, die die Größenordnung oder den Nachkommaanteil des Werts verlieren kann, braucht einen expliziten Cast (type)value. Eine Ausnahme solltest du kennen: int oder long in float sowie long in double sind implizit, obwohl sie Genauigkeit verlieren können: float f = 16_777_217; kompiliert und speichert 16777216.
Ausgabe:
9 -9
10
2
4
705032704
9.99
7 7.0 7
Drei Dinge solltest du dir merken. Ein Cast von Gleitkomma in Ganzzahl schneidet ab; er rundet nicht. Convert.ToInt32(double) rundet, und zwar mit Banker's Rounding (halbe Werte gehen zum geraden Nachbarn). Und ein Ganzzahl-Cast, der nicht passt, springt stillschweigend um, außer er läuft in einem checked-Kontext, wo er OverflowException wirft (siehe Datentypen).
int x = 3.7; ist ein Kompilierfehler (CS0266: cannot implicitly convert type 'double' to 'int', an explicit conversion exists). Damit fordert dich der Compiler auf, dich zwischen einem Cast und einer Rundungsmethode zu entscheiden.
Zahlen und andere Typen in String
Jeder Typ hat ToString(), und numerische Typen akzeptieren einen Formatstring. String-Interpolation nutzt dieselbe Formatierung:
Ausgabe:
42
000042
1234.50
1,234.50
$1,234.50
FF
1010
True
Order 000042: 1234.50
Die Formatcodes (D, F, N, C, X, P, E) und eigene Muster wie "0.00" werden unter String-Interpolation behandelt.
Zeichen und Booleans
Ausgabe:
7
55
7
7
A
True
False
1
False
(int)'7' ist 55, der Code des Zeichens, nicht 7. Darüber stolpert jeder, der die Ziffern einer Zahl addiert; ziehe '0' ab oder nimm char.GetNumericValue. bool.Parse akzeptiert "true" und "false" in beliebiger Schreibweise und sonst nichts ("yes" und "1" werfen eine Exception).
Referenzumwandlungen: Casts, as und is
Bei Klassentypen prüft ein Cast zur Laufzeit den tatsächlichen Typ des Objekts. Ein Upcast auf eine Basisklasse ist implizit. Ein Downcast auf eine abgeleitete Klasse braucht einen expliziten Cast, der InvalidCastException wirft, wenn das Objekt etwas anderes ist:
Ausgabe:
4242
True
Card ending 4242, 50.00
InvalidCastException
5
cannot unbox int as long
Nimm lieber is mit einer Variable, wenn du nach dem Typ verzweigen musst; das ist eine einzige Prüfung, kann nicht werfen, und die neue Variable ist nur dort im Gültigkeitsbereich, wo der Test erfolgreich war. Nimm einen einfachen Cast, wenn ein anderer Typ ein Bug wäre, der laut scheitern soll. Der Fall mit dem geboxten int erwischt Leute, die Zahlen aus object-Collections oder DataRow-Zellen lesen: Entboxe zuerst in den exakten Typ ((long)(int)boxed) oder nimm Convert.ToInt64(boxed), das jeden numerischen Typ verarbeitet.
Häufig gestellte Fragen
Wie wandle ich in C# einen String in ein int um?
Nimm int.TryParse(text, out int number), wenn der Text von einem Benutzer, aus einer Datei oder aus dem Netzwerk kommt: Es gibt false zurück, statt eine Exception zu werfen, wenn der Text keine gültige Zahl ist. Nimm int.Parse(text), wenn ungültiger Text ein Bug ist und eine Exception die richtige Reaktion. Convert.ToInt32(text) verhält sich wie int.Parse, gibt aber für null 0 zurück.
Was ist der Unterschied zwischen int.Parse und Convert.ToInt32?
Für Strings sind sie fast gleich: Beide werfen FormatException bei Text wie "abc" und OverflowException bei Zahlen außerhalb des Wertebereichs. Der Unterschied ist null: int.Parse(null) wirft ArgumentNullException, Convert.ToInt32(null) gibt 0 zurück. Convert.ToInt32 akzeptiert außerdem andere Typen (double, bool, object) und rundet ein double auf die nächste gerade Ganzzahl, statt abzuschneiden.
Was bedeutet „Input string was not in a correct format“?
Das ist die Meldung einer FormatException, die int.Parse, double.Parse oder Convert.ToInt32 werfen (ab .NET 8 lautet sie „The input string 'abc' was not in a correct format“ und zitiert den Text), wenn der Text keine Zahl im erwarteten Format ist: Buchstaben, ein leerer String, ein Dezimalpunkt beim Parsen eines int oder ein Tausendertrennzeichen. Wechsle zu TryParse, um fehlerhafte Eingaben ohne Exception zu behandeln, und prüfe, in welcher Kultur die Zahl geschrieben wurde.
Wie caste ich in C# ein double in ein int?
Schreibe einen expliziten Cast: int n = (int)price;. Der Cast schneidet in Richtung null ab, also ist (int)9.99 gleich 9 und (int)-9.99 gleich -9. Zum Runden nimm (int)Math.Round(price) und beachte, dass Math.Round halbe Werte standardmäßig zur nächsten geraden Zahl rundet; übergib MidpointRounding.AwayFromZero für kaufmännisches Runden.
Was ist der Unterschied zwischen as und einem Cast in C#?
Ein Cast (Dog)animal wirft InvalidCastException, wenn das Objekt kein Dog ist. animal as Dog gibt stattdessen null zurück, muss also von einer Null-Prüfung gefolgt werden und funktioniert nur mit Referenz- und Nullable-Typen. Die moderne Alternative ist das is-Muster: if (animal is Dog dog) { ... } prüft und wandelt in einem Schritt um.