从“System.Int32”转换为“System.Nullable`1 ]无效

Type t = typeof(int?); //will get this dynamically object val = 5; //will get this dynamically object nVal = Convert.ChangeType(val, t);//getting exception here 

在上面的代码中,我得到了InvalidCastException。 对于上面,我可以简单地写int? nVal = val int? nVal = val ,但上面的代码是dynamic执行的。

我得到一个包含在一个对象(这里为val)的值(非空types,如int,float等),我必须将其保存到另一个对象,通过将其转换为另一个types(可以或不可以为空) )。 什么时候

从“System.Int32”到“System.Nullable`1 [[System.Int32,mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089]]的转换无效。

一个int ,应该是可转换/可types转换为nullable int ,这里有什么问题?

您必须使用Nullable.GetUnderlyingType来获取Nullable.GetUnderlyingType基础types。

这是我用来克服ChangeType for Nullable限制的方法

 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); } 

非generics方法:

 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); } 

对于上面,我可以简单地写int? nVal = val

其实你也做不到 没有从objectNullable<int>隐式转换。 但是有一个从intNullable<int>的隐式转换,所以你可以这样写:

 int? unVal = (int)val; 

您可以使用Nullable.GetUnderlyingType方法。

返回指定可空types的基础types参数

genericstypes定义是一个types声明,如Nullable,它包含一个types参数列表,而types参数列表声明一个或多个types参数。 closures的genericstypes是一个types声明,其中为types参数指定了特定的types。

 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 

这里是一个DEMO

我想我应该解释为什么该function不起作用:

1-引发exception的行如下所示:

 throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", new object[] { value.GetType().FullName, targetType.FullName })); 

实际上是在数组Convert.ConvertTypes之后的函数search,看看targer是一个Enum,当没有find它时,抛出上面的exception。

2- Convert.ConvertTypes被初始化为:

 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) }; 

那么既然int? 不在ConvertTypes数组中,不是Enum引发的exception。

所以要恢复,为Convert.ChnageType函数工作,你有:

  1. 要转换的对象是IConvertible

  2. 目标types在ConvertTypes中,而不是Empty或者DBNull (对于这两个抛出exception有一个明确的testing)

此行为是因为int (和所有其他默认types)使用Convert.DefaultToType作为IConvertibale.ToType implementation. and here is the code of the implementation. and here is the code of the使用ILSpy extracted implementation. and here is the code of the DefaultToType implementation. and here is the code of the

 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 })); } 

另一方面,该转换是由Nullable类本身实现的,定义如下:

 public static implicit operator T?(T value) { return new T?(value); } public static explicit operator T(T? value) { return value.Value; }