| 

.NET C# Java Javascript Exception

3
Hallo Allerseites,
meine Frage ergibt sich aus nachfolgendem Quelltext (ich weiss das ich das Ganze auch anders lösen kann ich will aber wissen wieso das .Cast fehlschlägt):

void Main()
{
//1. Implizitze Umwandlung von Int in Long
int myInt = 1;
long myLong = myInt;
Console.WriteLine (myLong);

//2. Explizite Umwandlung von Long in Int
long myLong2 = 1;
int myInt2 = (int)myLong2 ;
Console.WriteLine (myLong2);


//3. InvalidCastException
//Intern wird ja nichts anderes gemacht als (TSource)element also das gleiche wie bei Beispiel 2. Also wieso knallt das?
int[] integers = {1,2,3};

IEnumerable<long> test = integers.Cast<long>();
Console.WriteLine (test);
}
31.03.2011
Thomas Sczyrba 1,4k 1 2 9
3 Antworten
2
.NET macht hier einen feinen Unterschied zwischen casten im Sinne von "behandle dieses Objekt, als wäre es vom Typ X" (Beispiel: string auf object casten) und Konvertierung (mach mir aus dem long einen int). Die Cast-Methode unterstützt nur die Casts im ersten Sinne (beachte: es geht auch schief, wenn Du versuchst, ein long[] in ein int[] auf diese Weise umzuwandeln). Ein int ist kein long und ein long auch kein int, sie können demnach nicht gecastet, sondern nur ineiander konvertiert werden (eine Richtung explizit, die andere implizit) - die Syntax dafür ist (in diesem Fall: leider) die selbe, aber es ist halt nicht ganz das gleiche.

Steht übrigens hier bei stackoverflow, und dort wird auch auf einen MSDN-Beitrag verlinkt, demzufolge es vor VS 2008 SP1 noch mit Wertkonvertierung funktioniert hat und danach geändert wurde.
31.03.2011
Matthias Hlawatsch 13,2k 4 9
thx. An alle interessierten: Die Links von Matthias sind hier sehr aufschlussreich. Demnach hat MS nach VS2008 SP1 die Wertekonvertierung entfernt da es zu Performanceproblemen gekommen ist.
Thomas Sczyrba 31.03.2011
1
Das Problem ist die Art und Weise, wie die Extension Methode Cast implementiert ist.

Was Du zuerst machst, ist ein Cast von einem Typen in einen anderen, bspw.

int i = 100;
long l = (long)i


Die Cast Methode arbeitet jedoch mit sog. boxed types, also mit Objekten.

int i = 100;
object o = (object) i;
long l = (long) o;


Hier bekommst Du nun auch eine InvalidCastException, weil man sich beim Design von C# eben entschieden hat, einen einmal geboxedten Typen nur wieder in den selben Typen zurückverwandeln zu lassen.

Hier sieht man, was der ILSpy für den CastIterator ausspuckt:


private static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source)
{
IEnumerator enumerator = source.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
object current = enumerator.Current;
yield return (TResult)current;
}
}
finally
{
IDisposable disposable = enumerator as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
yield break;
}
31.03.2011
CRegenschein 645 2 9
Ja das klingt logisch. Jetzt stellt sich mir natürlich die Frage was der Anlass für das boxing ist. Wenn ich mir mit Reflector die implementierung der Cast Methode anschaue sehe ich nichts das das Boxing veranlasst.
Thomas Sczyrba 31.03.2011
Die dafür verantwortliche Zeile sieht etwa so aus:

[code]this.<>2__current = (TResult)this.<obj>5__ab;[/code]
CRegenschein 31.03.2011
Darf ich fragen woher Du die Zeile hast? Im reflector kann ich sie weit und breit nicht finden.
Thomas Sczyrba 31.03.2011
Edit: Habe oben mal den CastIterator aus dem ILSpy rausgezogen. Da sieht man dass object current = verwendet wird
CRegenschein 31.03.2011
-1
Das Verhalten des cast-Versuchs von long in int ist vollkommen korrekt und muss in einer InvalidCastException enden. Einfach aus dem Grund, weil der von einem long-Wert belegte Speicher den verfügbaren Speicherbereich eines int bei weitem übersteigen kann.
Vergleiche einfach die Werte der Felder int.minValue zu long.minValue und int.maxValue zu long.maxValue. Dann sollte jede weitere Frage geklärt sein.
Zu deinem Beispielen mit implizit und explizit cast:
Hier hattetst du einfach "Glück", dass der derzeite Wert der long-Variablen von der int-Variablen aufgenommen werden konnte. Hättest du hier einen Wert verwendet, der die Größe von int.maxValue überschritten hätte, währe eine InvalidCastException die Folge.

Servus,
Klaus
31.03.2011
klaus_b 1,6k 3 7
klaus_b 1,6k 3 7
1
Deine Antwort ist nicht korrekt. Ein expliziter Cast von Long in Int funktioniert immer und verursacht maximal einen Datenverlust aber keine Exception. Das kannst Du selber hiermit testen:
//2. Explizite Umwandlung von Long in Int
long myLong2 = long.MaxValue ;
int myInt2 = (int)myLong2 ;
Console.WriteLine (myLong2);

Übrigens: Wenn Du statt einem Cast eine eine Arithmetische Funktion verwendest erhälst als ergebnis einer Exception wenn Du in einem Uncecked Kontext arbeitest: http://msdn.microsoft.com/de-de/library/khy08726%28v=vs.80%29.aspx
Thomas Sczyrba 31.03.2011

Stelle deine .net-Frage jetzt!
TOP TECHNOLOGIES CONSULTING GmbH