C# 从“System.Int32”到“System.Nullable”1[[System.Int32, mscorlib]] 的无效转换

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18015425/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:03:19  来源:igfitidea点击:

Invalid cast from 'System.Int32' to 'System.Nullable`1[[System.Int32, mscorlib]]

c#.netcastingtype-conversionnullable

提问by Brij

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.

我在上面的代码中收到 InvalidCastException。对于上面我可以简单地写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). When

我得到一个值(非空类型,如 int、float 等)包裹在一个对象(这里是 val)中,我必须通过将它转换为另一种类型(可以或不能为可空版本)来将它保存到另一个对象其中)。什么时候

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 ?

An int, 应该可以转换/类型转换为nullable int,这里有什么问题?

采纳答案by gzaxx

You have to use Nullable.GetUnderlyingTypeto get underlying type of Nullable.

您必须使用Nullable.GetUnderlyingType来获取Nullable.

This is the method I use to overcome limitation of ChangeTypefor Nullable

这是我用来克服ChangeTypefor限制的方法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);
}

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

回答by Soner G?nül

For above I could simply write int? nVal = val

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

Actually, you can't do that either. There is no implicit conversion from objectto Nullable<int>. But there isan implicit conversion from intto Nullable<int>so you can write this:

事实上,你也不能那样做。没有从object到 的隐式转换Nullable<int>。但是,从隐式转换intNullable<int>,所以你可以这样写:

int? unVal = (int)val;

You can use Nullable.GetUnderlyingTypemethod.

您可以使用Nullable.GetUnderlyingType方法。

Returns the underlying type argumentof 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. A closed generic type is a type declaration where a particular type is specified for a type parameter.

返回指定的可为空类型的基础类型参数

泛型类型定义是一种类型声明,例如 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

Here's a DEMO.

这是一个DEMO.

回答by Swift

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?is not in the ConvertTypes array and not an Enum the exception is thrown.

因此,由于int?不在 ConvertTypes 数组中,也不是在 Enum 中,因此抛出异常。

So to resume, for the function Convert.ChnageType to work you have:

所以要继续,为了让函数 Convert.ChnageType 工作,你有:

  1. The object to be converted is IConvertible

  2. The target type is within the ConvertTypes and not Emptynor DBNull(There is an explict test on those two with throw exception)

  1. 要转换的对象是 IConvertible

  2. 目标类型在 ConvertTypes 之内,而不是EmptyDBNull(有对这两个抛出异常的显式测试)

This behaviour is because int(and all other default types) uses Convert.DefaultToTypeas IConvertibale.ToType implementation. and here is the code of theDefaultToTypeextractedusing ILSpy

这种行为是因为int(和所有其他默认类型)使用Convert.DefaultToType作为 IConvertibale.ToType implementation. and here is the code of theDefaultToTypeextracted使用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
    }));
}

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