Laden...

Fehler oder gewolltes Verhalten in Convert.ChangeType(object, Type)

Erstellt von rollerfreak2 vor 11 Jahren Letzter Beitrag vor 11 Jahren 1.435 Views
rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 11 Jahren
Fehler oder gewolltes Verhalten in Convert.ChangeType(object, Type)

Hi,

ich habe was interessantes entdeckt und wollte euch mal Fragen ob das Verhalten so gewollt oder eher ein Fehler ist. Vorab der Code scheint so wie ich ihn jetzt schreibe sinnfrei, aber in unserem Fall ergibt das schon Sinn weil wir eine Methode haben die an einem T DataMember.GetValue<T>() implementiert. Im GetValue wird dann in verschiedenen Arten Convert.ChangeType(object, Type) aufgerufen.


IConvertible convertible = (IConvertible)Convert.ChangeType((long)5, typeof(object));
object obj = Convert.ChangeType((IConvertible)5, typeof(IConvertible));

Die erste Zeile geht zur Laufzeit aber die 2te wirft eine Exception die folgend lautet.

Fehlermeldung:
Invalid cast from 'System.Int32' to 'System.IConvertible'.

Die Meldung ist natürlich so nicht richtig und ich bin mal auf die Suche gegangen! Also im ChangeType wird das short in IConvertible gecastet und dann ganz unten wird return convertible.ToType(conversionType, provider); gerufen. Das wiederum geht dann auf object IConvertible.ToType(Type type, IFormatProvider provider)
das dann wiederrum Convert.DefaultToType(this, type, provider); called.

Nun steht in dieser Method oben die Abfrage


internal static object DefaultToType(IConvertible value, Type targetType, IFormatProvider provider)
{
    if (targetType == null)
    {
        throw new ArgumentNullException("targetType");
    }
    if (value.GetType() == targetType)
    {
        return value;
    }
.....
.....
throw new InvalidCastException(string.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("InvalidCast_FromTo"), new object[] { value.GetType().FullName, targetType.FullName }));

Die Abfrage value.GetType() == targetType liefert natürlich false weil GetType() short bzw. Int16 zurücl liefert. Aus meiner Sicht ist dort ein Fehler weil die Abfrage prüfen müsste ob der Typ von dem value.GetType() implementiert wird.

Also Fehler oder gewolltest Verhalten! In der MSDN steht zu der InvalidCastException nur folgendes:

This conversion is not supported.

-or-

value is null and conversionType is a value type.

-or-

value does not implement the IConvertible interface.

Again what learned...

F
10.010 Beiträge seit 2004
vor 11 Jahren

Die Meldung ist natürlich so nicht richtig und ich bin mal auf die Suche gegangen!

Doch, denn du versuchst hier einen short in einen IConvertible zu casten, und das geht eben nicht.
Es wird hier nicht noch irgendeine Funktion aufgerufen, sondern der im code stehende feste cast macht die Exception.

Statt ChangeType aufzurufen solltet ihr TypeConverter benutzen, da kann man schon vorab testen ob die Konvertierung überhaupt unterstützt wird.

Auch wenn du die frage nicht hören willst, wozu soll das ganze denn dienen?
Manchmal gibt es deutlich einfachere Wege.

rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 11 Jahren

Doch, denn du versuchst hier einen short in einen IConvertible zu casten, und das geht eben nicht.
Es wird hier nicht noch irgendeine Funktion aufgerufen, sondern der im code stehende feste cast macht die Exception.

Das ist nicht richtig! Int16 implementiert definiv IConvertible. Du kannst auch gern folgenden Code nehmen der erzeugt ebenfalls oben beschriebene Exception!


//das geht definitv
IConvertible convertible = (IConvertible)((System.Int16)5);
//das hier erzeugt oben beschrieben Exception
object obj = Convert.ChangeType((System.Int16)5, typeof(IConvertible));

Aus meiner Sicht also ein Fehler vom Framework zumindest stimmt die Exception nicht!

Auch wenn du die frage nicht hören willst, wozu soll das ganze denn dienen?

Wir haben eine Klasse die hat eine T GetValue<T>() Methode. Diese nutzt intern Convert.ChangeType je nachdem was T halt ist. Wenn man nun folgendes macht dann geht das nicht:


IConvertible convertible = member.GetValue<IConvertible>();

Das wiederum geht:


//hier kommt dann ein Int (default) zurück
IConvertible convertible = (IConvertible)member.GetValue<object>();

Die zweite Schreibweise ist aber a.M.S Quatsch, dient halt nur dazu die Exception zu umgehen!

Again what learned...

771 Beiträge seit 2009
vor 11 Jahren

N'abend,

meines Erachtens macht Convert.ChangeType mit einem Interface überhaupt keinen Sinn, sondern nur mit echten Typen - und darum kommt auch die Exception (denn was für einen "unkonkreten" Typ soll denn bei einem Interface zurückgeliefert werden?).

49.485 Beiträge seit 2005
vor 11 Jahren

Hallo rollerfreak2,

vermutlich hilft bei dem Verständnis dessen, was Cat gesagt hat, sich den Unterschied zwischen statischem und dynamischen Typ klar zu machen und zu beachten. Der statische Typ ist der Typ der Variable (oder des Ausdrucks), der dynamische Typ ist der Typ des Objekts. Wohlgemerkt "dynamisch" in Bezug auf die Variable, das bedeutet, dass im Allgemeinen erst zur Laufzeit feststeht, welche konkreten Typ das Objekt nun hat, auf das die Variable (gerade) referenziert. Der (statische) Typ der Variable selbst ändert sich nie, genauso wie der Typ eines einmal erzeugten Objekts sich nie ändert. Bei Werttypen stimmt der statische und der dynamische Typ immer überein.

Bei einem Cast auf IConvertible ändert sich der statische Typ, aber der dynamische Typ bleibt derselbe. Bei Convert.ChangeType wird der dynamische Typ geändert - genauer es wird ein neues Objekt von dem gewünschten (dynamischen) Typ zurückgegeben -, der statische Typ ist immer Object (weil das der Rückgabetyp ist). Ein neues Objekt kann man aber nur zu einem konkreten Typ erzeugen, nicht zu einem Interface - wie Cat gesagt hat.

herbivore