Hi Leute, habe eine Grundlagenfrage.
Gibt es einen Unterschied zwischen nachfolgenden Konvertierungen
und was muss man bedenken?:
int i;
byte b;
//(...)
b = Convert.ToByte(i);
checked { b = (byte)i; }
Ich habe das mal mit
Int16 i;
grob ausprobiert für einige Zahlen aus 32767 bis -32768. Scheint alles gleich. (Ein vollständiger Test dauert Ewigkeiten.)
Ich verwende gerne
b = (byte)i;
und bin mir bewusst, dass beim Überlauf der Teil beim Überlauf abgeschnitten wird. Den Umstand nutze ich auch gerne aus.
Nun lese ich, dass einige in den Compileroptionen die Überlaufsprüfungen einschalten, so dass aus
b = (byte)i;
automatisch
checked { b = (byte)i; }
wird. Alles hat ja seinen Grund. Wie macht Ihr das bzw. was haltet Ihr davon?
Ohne die Frage jetzt direkt beantworten zu können; du kannst ja mal einen Benchmark damit probieren, also die Zeit stoppen, die für Convert und für einen normalen Cast gebraucht wird.
Darüber hinaus könntest du dir anschauen, was der Compiler aus den beiden Aufrufen macht. Wenn er gut optimiert, dürften beide Aufrufe den gleichen Maschinencode ergeben.
Wissen tu ich das allerdings nicht. 🤔
Was sich immer wieder lohnt ist ein Block in einen Disassembler.
Convert.ToByte(char) prüft, ob das char ausserhalb des erlaubten Bereiches (> '\x00ff') ist, und wirft eine OverflowException, falls das der Fall ist. Wenn nicht wird dort auch gecastet: (Byte)value
LG pdelvo
Moinsen,
ich bevorzuge in geeigneten Fällen Convert.To...
Wenn das Argument aus irgendwelchen Gründen null ist oder sonstwie nicht passt, gibt Convert.To... den Default-Value des Typs zurück.
object o = null;
int i = (int)o; // -> wummmss!!!
int i = Convert.ToInt32(o); // -> i = 0;
Grüße
Christian
Hallo CoLo,
ich persönlich handhabe das ganze wie folgt:
Wenn ich es nicht mal vergesse, schalte ich in den Buildoptionen meiner Projekte immer die Option "Check for arithmetic over-/underflow" (unter "Build-Advanced" unter VS). Diese hat quasi den gleichen Effekt wie ein "großer" checked
-Block um den gesamten Code.
Hintergrund ist, dass man IMHO beim "normalen" Lesen von Code nicht über eventuelle Overflows nachdenkt. Bei der Ausführung des Codes wird somit sichergestellt, dass dieser keine "unangenehmen" Überraschungen enthält; ich kann davon ausgehen, dass kein Bug, der durch unabsichtlichen Overflow verursacht wird, unentdeckt bleibt.
Will ich hingegen bewusst Overflows ausnutzen, sodass "(sbyte) 255" auch tatsächlich "-1" ergibt, verwende ich für diese Stellen unchecked
. Erfahrunsgemäß beschränkt sich dies auf wenige Klassen bzw. Methoden (die dann Algorithmen auf Bytebene implementieren).
Die Convert Klasse verwende ich recht selten; hauptsächlich, wenn ich wie im Beispiel von chriscolm von Object aus casten will, und nicht genau weiß, ob sich jetzt hinter dem Objekt ein Integer, ein Byte oder doch etwas anderes verbirgt.
Convert.ToXXX nutzt ja soweit ich mich erinnern kann auch IConvertible<T>, was die normalen Casts nicht tun.
Vielen dank für die Antworten.
Ich glaube ich werde in Zukunft mehr mit checked arbeiten. Auf jeden Fall mehr darüber Nachdenken. Vielleicht werde ich später mal die Überlaufsprüfung in den Compileroptionen einschalten.
Gruß, CoLo =)
Hi CoLo,
ich glaube, der Hinweis von winSharp93 war genau andersherum gemeint. Die Überlaufprüfung in den Build-Optionen sollte immer angeschaltet sein, denn damit bekommst du Hinweise auf fehlerhaften Code. In den allermeisten Fällen ist ein Überlauf nämlich nicht erwünscht. Nur in den wenigen Fällen wie bei der Hashcode-Berechnung solltest du dann unchecked-Blöcke verwenden, um explizit die Überlaufprüfung auszuschalten.
Christian
Weeks of programming can save you hours of planning