Type t = typeof(int?); //will get this dynamically
object val = 5; //will get this dynamically
object nVal = Convert.ChangeType(val, t);//getting exception here
Ich erhalte InvalidCastException im obigen Code. Für oben könnte ich einfach schreiben int? nVal = val
, aber oben Code wird dynamisch ausgeführt.
Ich erhalte einen Wert (vom nicht nullbaren Typ wie int, float usw.), der in ein Objekt eingewickelt ist (hier val), und ich muss ihn in einem anderen Objekt speichern, indem ich ihn in einen anderen Typ umwandle (der eine nullbare Version sein kann oder nicht) davon). Wann
Ungültige Umwandlung von 'System.Int32' in 'System.Nullable`1 [[System.Int32, mscorlib, Version = 4.0.0.0, Kultur = neutral, PublicKeyToken = b77a5c561934e089]]'.
An int
, sollte konvertierbar / typgießbar sein nullable int
, worum geht es hier?
Nullable<T>
implementiert Coz nichtIConvertible
Antworten:
Sie müssen verwenden
Nullable.GetUnderlyingType
, um den zugrunde liegenden Typ von zu erhaltenNullable
.Dies ist die Methode, mit der ich die Begrenzung von
ChangeType
for überwindeNullable
public static T ChangeType<T>(object value) { var t = typeof(T); if (t.IsGenericType && t.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) { if (value == null) { return default(T); } t = Nullable.GetUnderlyingType(t); } return (T)Convert.ChangeType(value, t); }
nicht generische Methode:
public static object ChangeType(object value, Type conversion) { var t = conversion; if (t.IsGenericType && t.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) { if (value == null) { return null; } t = Nullable.GetUnderlyingType(t); } return Convert.ChangeType(value, t); }
quelle
object nVal = ChangeType<int?>(val)
Hier muss ich der Methode das generische Argument (T) mitteilen, aber ich habet
(oder typeof (dataType)) zur Verfügung. Wie würde ich Ihre ChangeType-Methode in meinem Szenario aufrufen?default(conversion)
, scheint ein ähnliches Problem zu sein.return null
ist nicht dasselbe wiedefault(T)
. Wenn Sie mit Strukturen zu tun haben, sind das völlig andere Dinge.Das kann man eigentlich auch nicht. Es gibt keine implizite Konvertierung von
object
nachNullable<int>
. Es gibt jedoch eine implizite Konvertierung vonint
nach,Nullable<int>
sodass Sie Folgendes schreiben können:int? unVal = (int)val;
Sie können
Nullable.GetUnderlyingType
Methode verwenden.Type t = typeof(int?); //will get this dynamically Type u = Nullable.GetUnderlyingType(t); object val = 5; //will get this dynamically object nVal = Convert.ChangeType(val, u);// nVal will be 5
Hier ist ein
DEMO
.quelle
Ich denke, ich sollte erklären, warum die Funktion nicht funktioniert:
1- Die Zeile, die die Ausnahme auslöst, lautet wie folgt:
throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", new object[] { value.GetType().FullName, targetType.FullName }));
Tatsächlich sieht die Funktionssuche im Array Convert.ConvertTypes danach, ob das Targer eine Aufzählung ist, und wenn nichts gefunden wird, löst es die obige Ausnahme aus.
2- Die Convert.ConvertTypes werden wie folgt initialisiert:
Convert.ConvertTypes = new RuntimeType[] { (RuntimeType)typeof(Empty), (RuntimeType)typeof(object), (RuntimeType)typeof(DBNull), (RuntimeType)typeof(bool), (RuntimeType)typeof(char), (RuntimeType)typeof(sbyte), (RuntimeType)typeof(byte), (RuntimeType)typeof(short), (RuntimeType)typeof(ushort), (RuntimeType)typeof(int), (RuntimeType)typeof(uint), (RuntimeType)typeof(long), (RuntimeType)typeof(ulong), (RuntimeType)typeof(float), (RuntimeType)typeof(double), (RuntimeType)typeof(decimal), (RuntimeType)typeof(DateTime), (RuntimeType)typeof(object), (RuntimeType)typeof(string) };
Da sich das
int?
also nicht im ConvertTypes-Array und nicht in einer Aufzählung befindet, wird die Ausnahme ausgelöst.Um fortzufahren, damit die Funktion Convert.ChnageType funktioniert, haben Sie:
Das zu konvertierende Objekt ist IConvertible
Der Zieltyp befindet sich innerhalb der ConvertTypes und nicht
Empty
nochDBNull
(Es gibt einen expliziten Test für diese beiden mit Wurfausnahme)Dieses Verhalten ist darauf zurückzuführen, dass
int
(und alle anderen Standardtypen)Convert.DefaultToType
IConvertibale.ToTypeimplementation. and here is the code of the
DefaultToTypeextracted
verwendetILSpy
internal static object DefaultToType(IConvertible value, Type targetType, IFormatProvider provider) { if (targetType == null) { throw new ArgumentNullException("targetType"); } RuntimeType left = targetType as RuntimeType; if (left != null) { if (value.GetType() == targetType) { return value; } if (left == Convert.ConvertTypes[3]) { return value.ToBoolean(provider); } if (left == Convert.ConvertTypes[4]) { return value.ToChar(provider); } if (left == Convert.ConvertTypes[5]) { return value.ToSByte(provider); } if (left == Convert.ConvertTypes[6]) { return value.ToByte(provider); } if (left == Convert.ConvertTypes[7]) { return value.ToInt16(provider); } if (left == Convert.ConvertTypes[8]) { return value.ToUInt16(provider); } if (left == Convert.ConvertTypes[9]) { return value.ToInt32(provider); } if (left == Convert.ConvertTypes[10]) { return value.ToUInt32(provider); } if (left == Convert.ConvertTypes[11]) { return value.ToInt64(provider); } if (left == Convert.ConvertTypes[12]) { return value.ToUInt64(provider); } if (left == Convert.ConvertTypes[13]) { return value.ToSingle(provider); } if (left == Convert.ConvertTypes[14]) { return value.ToDouble(provider); } if (left == Convert.ConvertTypes[15]) { return value.ToDecimal(provider); } if (left == Convert.ConvertTypes[16]) { return value.ToDateTime(provider); } if (left == Convert.ConvertTypes[18]) { return value.ToString(provider); } if (left == Convert.ConvertTypes[1]) { return value; } if (left == Convert.EnumType) { return (Enum)value; } if (left == Convert.ConvertTypes[2]) { throw new InvalidCastException(Environment.GetResourceString("InvalidCast_DBNull")); } if (left == Convert.ConvertTypes[0]) { throw new InvalidCastException(Environment.GetResourceString("InvalidCast_Empty")); } } throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", new object[] { value.GetType().FullName, targetType.FullName })); }
Andererseits wird die Besetzung von der Nullable-Klasse selbst implementiert und die Definition lautet:
public static implicit operator T?(T value) { return new T?(value); } public static explicit operator T(T? value) { return value.Value; }
quelle