从 'System.Int32' 到 'System.Nullable`1[[System.Int32, mscorlib]] 的无效转换
Posted
技术标签:
【中文标题】从 \'System.Int32\' 到 \'System.Nullable`1[[System.Int32, mscorlib]] 的无效转换【英文标题】:Invalid cast from 'System.Int32' to 'System.Nullable`1[[System.Int32, mscorlib]]从 'System.Int32' 到 'System.Nullable`1[[System.Int32, mscorlib]] 的无效转换 【发布时间】:2022-01-12 13:25:52 【问题描述】: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、float 等)包裹在一个对象(此处为 val)中,我必须通过将其转换为另一种类型(可以或不能)将其保存到另一个对象是它的可空版本)。当
从 'System.Int32' 到 'System.Nullable`1[[System.Int32, mscorlib,版本=4.0.0.0,文化=中性, PublicKeyToken=b77a5c561934e089]]'。
一个int
,应该可以转换/类型转换为nullable int
,这里有什么问题?
【问题讨论】:
我猜可能是因为Nullable<T>
没有实现 IConvertible
这是相当基本的。 Nullable 是特殊的,当你把它放在一个对象中时,它要么变成空,要么变成值类型的装箱值。所以要求一个int?存储在一个对象中是没有意义的。只需要求 int。
【参考方案1】:
您必须使用Nullable.GetUnderlyingType
来获取Nullable
的基础类型。
这是我用来克服ChangeType
对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);
非泛型方法:
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);
【讨论】:
要使用你的方法,我需要做类似的事情:object nVal = ChangeType<int?>(val)
,在这里我需要告诉方法关于通用参数(T),但我有t
(或typeof( dataType)) 供我使用。在我的场景中如何调用您的 ChangeType 方法?
添加了非通用版本。看看有没有帮助。
在default(conversion)
出现编译错误,似乎是类似的问题。
小心@gzaxx,因为return null
与default(T)
不同。如果您正在处理结构,它们是完全不同的东西。
非泛型版本将装箱结构和原始类型(因为它需要并返回对象),因此返回 null 是有效的。任何调用函数的人都必须自己处理。【参考方案2】:
对于上面我可以简单地写 int? nVal = 值
实际上,你也不能这样做。没有从object
到Nullable<int>
的隐式转换。但是是从int
到Nullable<int>
的隐式转换,所以你可以这样写:
int? unVal = (int)val;
你可以使用Nullable.GetUnderlyingType
方法。
返回指定可空类型的基础类型参数。
泛型类型定义是一种类型声明,例如 Nullable, 包含类型参数列表和类型参数列表 声明一个或多个类型参数。封闭的泛型类型是一种类型 为类型参数指定特定类型的声明。
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
。
【讨论】:
如果对象 val = null;【参考方案3】:我想我应该解释一下为什么该功能不起作用:
1- 抛出异常的行如下:
throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", new object[]
value.GetType().FullName,
targetType.FullName
));
实际上,函数在数组 Convert.ConvertTypes 中搜索之后,它会查看目标是否为 Enum,当没有找到任何内容时,它会抛出上述异常。
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,因此会引发异常。
所以要恢复,要让 Convert.ChnageType 函数正常工作:
要转换的对象是IConvertible
目标类型在 ConvertTypes 中,而不是 Empty
或 DBNull
(对这两个类型进行显式测试并抛出异常)
这种行为是因为int
(和所有其他默认类型)使用Convert.DefaultToType
作为IConvertibale.ToType implementation. and here is the code of the
DefaultToTypeextracted
使用ILSpy
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;
【讨论】:
以上是关于从 'System.Int32' 到 'System.Nullable`1[[System.Int32, mscorlib]] 的无效转换的主要内容,如果未能解决你的问题,请参考以下文章
从具体化的“System.Int32”类型到“System.Double”类型的指定转换无效
通过 AJAX 将 JSON 数据发布到 Web API 失败,并显示“无法将 JSON 值转换为 System.Int32”
从 ASP.NET 调用 Oracle 存储过程时,无法将“System.Int32[]”类型的对象转换为“System.IConvertible”类型
过程返回错误:无法将 System.Int32 转换为 System.Int32[]
“System.Int16”类型的对象无法转换为“System.Nullable”1[System.Int32] 类型
InvalidCastException:无法将“System.DBNull”类型的对象转换为“System.Nullable`1[System.Int32]”[重复]