Type t = typeof(int?); //will get this dynamically
object val = 5; //will get this dynamically
object nVal = Convert.ChangeType(val, t);//getting exception here
I am getting InvalidCastException in above code. For above I could simply write int? nVal = val, but above code is executing dynamically.
I am getting a value(of non nullable type like int, float, etc) wrapped up in an object (here val), and I have to save it to another object by casting it to another type(which can or cannot be nullable version of it). When
Invalid cast from 'System.Int32' to 'System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'.
An int, should be convertible/type-castable to nullable int, what is the issue here ?

Nullable<T>doesn't implementIConvertibleRespuestas:
You have to use
Nullable.GetUnderlyingTypeto get underlying type ofNullable.This is the method I use to overcome limitation of
ChangeTypeforNullablepublic 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); }non generic method:
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); }fuente
object nVal = ChangeType<int?>(val), here I need to tell the method about the generic argument(T), but I havet(or typeof(dataType)) at my disposal. How would I call your ChangeType method in my scenario ?default(conversion), seems like similar issue.return nullis not the same asdefault(T). If you're dealing with structs they are completely different things.Actually, you can't do that either. There is no implicit conversion from
objecttoNullable<int>. But there is an implicit conversion frominttoNullable<int>so you can write this:int? unVal = (int)val;You can use
Nullable.GetUnderlyingTypemethod.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 5Here's a
DEMO.fuente
I think I should explain why the function does not work:
1- The line that throw the exception is as follows:
throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", new object[] { value.GetType().FullName, targetType.FullName }));in fact the function search in the array Convert.ConvertTypes after that it see if the targer is an Enum and when nothing is found it throw the exception above.
2- the Convert.ConvertTypes is initialized as:
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) };So since the
int?is not in the ConvertTypes array and not an Enum the exception is thrown.So to resume, for the function Convert.ChnageType to work you have:
The object to be converted is IConvertible
The target type is within the ConvertTypes and not
EmptynorDBNull(There is an explict test on those two with throw exception)This behaviour is because
int(and all other default types) usesConvert.DefaultToTypeas IConvertibale.ToTypeimplementation. and here is the code of theDefaultToTypeextractedusingILSpyinternal 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 })); }in other hand the cast is implemented by Nullable class itself and the definition is:
public static implicit operator T?(T value) { return new T?(value); } public static explicit operator T(T? value) { return value.Value; }fuente