Hallo zu diesem kleinen Tutorial.
Häufig sehe ich hier im Forum, dass sich Leute nicht sicher sind, welche Art der Konvertierung sie verwenden sollen, bzw. auch Fälle, bei denen komplett unsauber konvertiert wird. Es gibt aber ein paar einfache Regeln, an die man scih dabei halten kann, um definitiv alles richtig zu machen. Diese treffen sowohl auf VB.Net alsauch auf C# zu, weshalb ich hier beides besprechen werde.
Zahl -> String
Eine der am häufigsten vorkommenden Fälle von Konvertierungen ist du Umwandlung einer Zahl in einen String. Darunter fallen auch die Typen DateTime und Char. Zuweilen sieht man hier dann sowas:
So solltet ihr es definitiv nicht machen. Bei allen Zahlentypen und auch bei DateTime und Char ist die ToString-Methode entsprechend überschrieben worden:
Die ToString-Methode bietet euch Formatierungsmöglichkeiten und ist außerdem das Standardverfahren (dazu kommen wir später noch genauer).
Das C#-Äquivalent hierzu wäre (wobei ich den Fehler eigentlich noch nie in nem C#-Code gesehen hab):
Der DateTime-Typ bietet euch zusätzlich noch weitere Funktionen, eine Stringdarstellung zu bekommen, außer ToString. Diese wären z.B. ToLongTimeString und ToShortTimeString, schaut euch den Typen einfach bei Bedarf mal an.
String -> Zahl
Auch dies ist ein oft auftretender Fall. Besonders beliebt ist hier offensichtlich sowas:
Es sei gesagt, dass dies zwar theoretisch möglich, aber nicht sehr schön ist. CInt wie auch alle anderen C...-Funktionen sind Kurzformen von CType, so entspräche z.B. CInt(bla) CType(bla, Integer). CType prüft zuerst auf eine Implementierung von IConvertible und dann per Reflection auf einen TypeConverter. Beides existiert zwar für die Zahlentypen, jedoch erzeugt das einen unnötigen Overhead.
Stattdessen sollte man die Parse- bzw. TryParse-Funktion des jeweiligen Zahlentyps (funktioniert auch bei DateTime) verwenden, die zusätzlich auch noch mehr Optionen bietet:
In C# wäre es dann das hier:
Zahl -> Zahl
Ebenfalls ein klassischer Anwendungsfall. Entgegen der Meinung einiger Leute ist es hier vollkommen in Ordnung, CInt usw zu verwenden. Wir erinnern uns, dies sind nur Kurzformen für CType, und im Falle der Zahlen gibt es wirklich nur die Möglichkeit über IConvertible und TypeConverter.
An dieser Stelle wird auch ab und zu die Convert-Klasse in den Raum geworfen, zu dieser werde ich mich aber später noch detailliert äußern.
Beliebige Klasse/Struktur -> String
Neben Zahlen und Daten will man womöglich auch andere Typen in ihre Stringdarstellung konvertieren. Hier sollten wir nun auf keinen Fall CStr verwenden, denn das basiert ja, wie schon gesagt, auf CType. Die meisten Programmierer überschreiben, wenn sie eine Stringkonvertierung vorsehen, nur die ToString-Funktion, erstellen aber keinen TypeConverter und implementieren auch kein IConvertible. Deswegen würde CStr an dieser Stelle einen Fehler auslösen. Also immer schön ToString für sowas benutzen, so wurde das Framework designt.
Macht also nie sowas:
Und in C# dann entsprechend nicht sowas:
String -> Beliebige Klasse/Struktur
Hier haben wir einen ähnlichen Fall vorliegen, wie bei String -> Zahl. Wenn der Ersteller einer Klasse oder Struktur vorgesehen hat, eine Konvertierung aus String zuzulassen, so wir er höchstwahrscheinlich eine Parse- bzw. TryParse-Funktion implementiert haben, seht also zuerst mal danach. Sollte eine solche Funktion nicht existieren, könnt ihr nach einem Konstruktor suchen, der einen String entgegennimmt, und als letzte Alternative dann noch nach IConvertible und TypeConverter (obwohl das dann sehr unwahrscheinlich ist, wenn schon keine Parse-Funktion existiert).
Findet ihr nichts dergleichen, so wird eine Konvertierung aus einem String wohl nicht vorgesehen sein.
Sonderfall: Convert-Klasse
Neben den ganzen oben genannten Konvertierungsoptionen gibt es auch noch die Convert-Klasse. Diese benötigt man im Normalfall nicht, da die Möglichkeiten von ToString, Parse usw. ausreichen. Es gibt jedoch spezielle Fälle, in denen die Convert-Klasse nützlich wird. Wollt ihr z.B. einen String in eine Zahl konvertieren oder umgekehrt, aber eine andere Basis als 10 oder 16 (die einzigen von ToString und Parse unterstützten) verwenden? Convert.ToString und Convert.To<Zahlentyp> besitzen Überladungen, bei denen man die Basis angeben kann.
Wenn aber kein Zwang besteht, Convert zu verwenden, weil die Funktionalität auch durch eine der oben genannten Funktionen gegeben ist, so sehe zumindest ich Convert als "weniger objektorientiert" an, ist aber streng genommen Geschmackssache.
Sonderfall: Boxing und Polymorphie
Es gibt noch den Fall, dass sich ein Objekt eines bestimmten Typs in einer Variable vom Typ Object oder von einem Basistypen befindet. In diesem Fall ist keine der oben genannten Konvertierungen angebracht, sondern DirectCast. DirectCast "holt" sozusagen das Objekt aus der Variable raus, ohne es aber tatsächlich zu konvertieren. Es handelt sich also um gar keine Konvertierung im eigentlichen Sinne, sondern viel mehr um eine "Uminterpretation" des entsprechenden Objektes.
Enthält die Variable ein Objekt, das nicht vom Zieltypen oder von einem abgeleiteten Typen des Zieltypen ist, so wird eine Exception ausgelöst.
Und so mit Basisklassen-Variable:
Alternativ gibt es auch noch TryCast, das im Prinzip genauso funktioniert, wie DirectCast, nur dass im Falle einer Typinkopatibilität keine Exception geworfen wird, sondern stattdessen Nothing zurückgegeben wird. Wenn man also vor einem DirectCast eine Typüberprüfung mit Typeof stehen hat, so ist dies ein Zeichen dafür, dass man doch lieber TryCast verwenden und dann auf Nothing prüfen sollte, da dies dann performanter ist.
C# besitzt ebenfalls solche Konvertierungsoperatoren.
TryCast wird hier durch den as-Operator dargestellt. Hier müsst ihr aber aufpassen, das funktioniert nur, wenn es sich um einen Referenztypen handelt (Klasse oder Interface), bei Wertetypen (Strukturen, Enums) könt ihr den as-Operator nicht verwenden. Stattdessen nehmt ihr dort dann die Standardkonvertierung, wie hier gezeigt:
Rest
Für alle Restlichen Konvertierungen, also wenn weder Zahlentypen, noch Strings, noch Boxing beteiligt ist, verwendet man in VB dann CType und in C# die Standardkonvertierung (z.B. (int)). Das setzt natürlich voraus, dass eine entsprechende Konvertierungsaktion überhaupt möglich ist.
Ich hoffe wie immer, ich konnte euren Horizont etwas erweitern. Bei Fragen einfach fragen.
Häufig sehe ich hier im Forum, dass sich Leute nicht sicher sind, welche Art der Konvertierung sie verwenden sollen, bzw. auch Fälle, bei denen komplett unsauber konvertiert wird. Es gibt aber ein paar einfache Regeln, an die man scih dabei halten kann, um definitiv alles richtig zu machen. Diese treffen sowohl auf VB.Net alsauch auf C# zu, weshalb ich hier beides besprechen werde.
Zahl -> String
Eine der am häufigsten vorkommenden Fälle von Konvertierungen ist du Umwandlung einer Zahl in einen String. Darunter fallen auch die Typen DateTime und Char. Zuweilen sieht man hier dann sowas:
So solltet ihr es definitiv nicht machen. Bei allen Zahlentypen und auch bei DateTime und Char ist die ToString-Methode entsprechend überschrieben worden:
Die ToString-Methode bietet euch Formatierungsmöglichkeiten und ist außerdem das Standardverfahren (dazu kommen wir später noch genauer).
Das C#-Äquivalent hierzu wäre (wobei ich den Fehler eigentlich noch nie in nem C#-Code gesehen hab):
Der DateTime-Typ bietet euch zusätzlich noch weitere Funktionen, eine Stringdarstellung zu bekommen, außer ToString. Diese wären z.B. ToLongTimeString und ToShortTimeString, schaut euch den Typen einfach bei Bedarf mal an.
String -> Zahl
Auch dies ist ein oft auftretender Fall. Besonders beliebt ist hier offensichtlich sowas:
Es sei gesagt, dass dies zwar theoretisch möglich, aber nicht sehr schön ist. CInt wie auch alle anderen C...-Funktionen sind Kurzformen von CType, so entspräche z.B. CInt(bla) CType(bla, Integer). CType prüft zuerst auf eine Implementierung von IConvertible und dann per Reflection auf einen TypeConverter. Beides existiert zwar für die Zahlentypen, jedoch erzeugt das einen unnötigen Overhead.
Stattdessen sollte man die Parse- bzw. TryParse-Funktion des jeweiligen Zahlentyps (funktioniert auch bei DateTime) verwenden, die zusätzlich auch noch mehr Optionen bietet:
In C# wäre es dann das hier:
Zahl -> Zahl
Ebenfalls ein klassischer Anwendungsfall. Entgegen der Meinung einiger Leute ist es hier vollkommen in Ordnung, CInt usw zu verwenden. Wir erinnern uns, dies sind nur Kurzformen für CType, und im Falle der Zahlen gibt es wirklich nur die Möglichkeit über IConvertible und TypeConverter.
An dieser Stelle wird auch ab und zu die Convert-Klasse in den Raum geworfen, zu dieser werde ich mich aber später noch detailliert äußern.
Beliebige Klasse/Struktur -> String
Neben Zahlen und Daten will man womöglich auch andere Typen in ihre Stringdarstellung konvertieren. Hier sollten wir nun auf keinen Fall CStr verwenden, denn das basiert ja, wie schon gesagt, auf CType. Die meisten Programmierer überschreiben, wenn sie eine Stringkonvertierung vorsehen, nur die ToString-Funktion, erstellen aber keinen TypeConverter und implementieren auch kein IConvertible. Deswegen würde CStr an dieser Stelle einen Fehler auslösen. Also immer schön ToString für sowas benutzen, so wurde das Framework designt.
Macht also nie sowas:
String -> Beliebige Klasse/Struktur
Hier haben wir einen ähnlichen Fall vorliegen, wie bei String -> Zahl. Wenn der Ersteller einer Klasse oder Struktur vorgesehen hat, eine Konvertierung aus String zuzulassen, so wir er höchstwahrscheinlich eine Parse- bzw. TryParse-Funktion implementiert haben, seht also zuerst mal danach. Sollte eine solche Funktion nicht existieren, könnt ihr nach einem Konstruktor suchen, der einen String entgegennimmt, und als letzte Alternative dann noch nach IConvertible und TypeConverter (obwohl das dann sehr unwahrscheinlich ist, wenn schon keine Parse-Funktion existiert).
Findet ihr nichts dergleichen, so wird eine Konvertierung aus einem String wohl nicht vorgesehen sein.
Sonderfall: Convert-Klasse
Neben den ganzen oben genannten Konvertierungsoptionen gibt es auch noch die Convert-Klasse. Diese benötigt man im Normalfall nicht, da die Möglichkeiten von ToString, Parse usw. ausreichen. Es gibt jedoch spezielle Fälle, in denen die Convert-Klasse nützlich wird. Wollt ihr z.B. einen String in eine Zahl konvertieren oder umgekehrt, aber eine andere Basis als 10 oder 16 (die einzigen von ToString und Parse unterstützten) verwenden? Convert.ToString und Convert.To<Zahlentyp> besitzen Überladungen, bei denen man die Basis angeben kann.
Wenn aber kein Zwang besteht, Convert zu verwenden, weil die Funktionalität auch durch eine der oben genannten Funktionen gegeben ist, so sehe zumindest ich Convert als "weniger objektorientiert" an, ist aber streng genommen Geschmackssache.
Sonderfall: Boxing und Polymorphie
Es gibt noch den Fall, dass sich ein Objekt eines bestimmten Typs in einer Variable vom Typ Object oder von einem Basistypen befindet. In diesem Fall ist keine der oben genannten Konvertierungen angebracht, sondern DirectCast. DirectCast "holt" sozusagen das Objekt aus der Variable raus, ohne es aber tatsächlich zu konvertieren. Es handelt sich also um gar keine Konvertierung im eigentlichen Sinne, sondern viel mehr um eine "Uminterpretation" des entsprechenden Objektes.
Enthält die Variable ein Objekt, das nicht vom Zieltypen oder von einem abgeleiteten Typen des Zieltypen ist, so wird eine Exception ausgelöst.
Und so mit Basisklassen-Variable:
Alternativ gibt es auch noch TryCast, das im Prinzip genauso funktioniert, wie DirectCast, nur dass im Falle einer Typinkopatibilität keine Exception geworfen wird, sondern stattdessen Nothing zurückgegeben wird. Wenn man also vor einem DirectCast eine Typüberprüfung mit Typeof stehen hat, so ist dies ein Zeichen dafür, dass man doch lieber TryCast verwenden und dann auf Nothing prüfen sollte, da dies dann performanter ist.
C# besitzt ebenfalls solche Konvertierungsoperatoren.
TryCast wird hier durch den as-Operator dargestellt. Hier müsst ihr aber aufpassen, das funktioniert nur, wenn es sich um einen Referenztypen handelt (Klasse oder Interface), bei Wertetypen (Strukturen, Enums) könt ihr den as-Operator nicht verwenden. Stattdessen nehmt ihr dort dann die Standardkonvertierung, wie hier gezeigt:
Rest
Für alle Restlichen Konvertierungen, also wenn weder Zahlentypen, noch Strings, noch Boxing beteiligt ist, verwendet man in VB dann CType und in C# die Standardkonvertierung (z.B. (int)). Das setzt natürlich voraus, dass eine entsprechende Konvertierungsaktion überhaupt möglich ist.
Ich hoffe wie immer, ich konnte euren Horizont etwas erweitern. Bei Fragen einfach fragen.
Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Artentus“ ()