[英]Invalid cast from 'System.Int32' to 'System.Nullable`1[[System.Int32, mscorlib]]
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.我在上面的代码中收到 InvalidCastException。 For above I could simply write
int? nVal = val
对于上面我可以简单地写
int? nVal = val
int? nVal = val
, but above code is executing dynamically. int? nVal = val
,但上面的代码是动态执行的。
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).我得到一个值(非空类型,如 int、float 等)包裹在一个对象(这里是 val)中,我必须通过将它转换为另一种类型(可以或不能为可空版本)来将它保存到另一个对象其中)。 When
什么时候
Invalid cast from 'System.Int32' to 'System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'.
从“System.Int32”到“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 ?一个
int
,应该是可转换/类型转换为nullable int
,这里有什么问题?
You have to use Nullable.GetUnderlyingType
to get underlying type of Nullable
.你必须使用
Nullable.GetUnderlyingType
得到基本类型的Nullable
。
This is the method I use to overcome limitation of ChangeType
for Nullable
这是我用来克服
Nullable
的ChangeType
限制的方法
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);
}
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);
}
For above I could simply write int?
对于上面我可以简单地写 int? nVal = val
nVal = val
Actually, you can't do that either.事实上,你也不能那样做。 There is no implicit conversion from
object
to Nullable<int>
.没有从
object
到Nullable<int>
隐式转换。 But there is an implicit conversion from int
to Nullable<int>
so you can write this:但是,有一个从隐式转换
int
至Nullable<int>
,所以你可以这样写:
int? unVal = (int)val;
You can use Nullable.GetUnderlyingType
method.您可以使用
Nullable.GetUnderlyingType
方法。
Returns the underlying type argument of the specified nullable type.
返回指定的可为空类型的基础类型参数。
A generic type definition is a type declaration, such as Nullable, that contains a type parameter list, and the type parameter list declares one or more type parameters.
泛型类型定义是一种类型声明,例如 Nullable,它包含一个类型参数列表,并且类型参数列表声明一个或多个类型参数。 A closed generic type is a type declaration where a particular type is specified for a type parameter.
封闭泛型类型是一种类型声明,其中为类型参数指定了特定类型。
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
I think I should explain why the function does not work:我想我应该解释为什么该功能不起作用:
1- The line that throw the exception is as follows: 1- 抛出异常的行如下:
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.实际上,函数在数组 Convert.ConvertTypes 中搜索之后,它会查看目标是否是 Enum,当没有找到任何东西时,它会抛出上面的异常。
2- the Convert.ConvertTypes is initialized as: 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)
};
So since the int?
那么自从
int?
is not in the ConvertTypes array and not an Enum the exception is thrown.不在 ConvertTypes 数组中,也不是在 Enum 中抛出异常。
So to resume, for the function Convert.ChnageType to work you have:所以要继续,为了让函数 Convert.ChnageType 工作,你有:
The object to be converted is IConvertible要转换的对象是 IConvertible
The target type is within the ConvertTypes and not Empty
nor DBNull
(There is an explict test on those two with throw exception)目标类型在 ConvertTypes 内,而不是
Empty
或DBNull
(对这两个有显式测试并抛出异常)
This behaviour is because int
(and all other default types) uses Convert.DefaultToType
as IConvertibale.ToType implementation. and here is the code of the
这种行为是因为
int
(和所有其他默认类型)使用Convert.DefaultToType
作为 IConvertibale.ToType implementation. and here is the code of the
implementation. and here is the code of the
DefaultToType extracted
using ILSpy
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
}));
}
in other hand the cast is implemented by Nullable class itself and the definition is:另一方面,转换是由 Nullable 类本身实现的,定义是:
public static implicit operator T?(T value)
{
return new T?(value);
}
public static explicit operator T(T? value)
{
return value.Value;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.