简体   繁体   English

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

[英]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这是我用来克服NullableChangeType限制的方法

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> .没有从objectNullable<int>隐式转换。 But there is an implicit conversion from int to Nullable<int> so you can write this:但是,有一个从隐式转换intNullable<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

Here's a DEMO .这是一个DEMO

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 工作,你有:

  1. The object to be converted is IConvertible要转换的对象是 IConvertible

  2. The target type is within the ConvertTypes and not Empty nor DBNull (There is an explict test on those two with throw exception)目标类型在 ConvertTypes 内,而不是EmptyDBNull (对这两个有显式测试并抛出异常)

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.

相关问题 类型&#39;System.Int16&#39;的对象不能转换为类型&#39;System.Nullable`1 [System.Int32] - Object of type 'System.Int16' cannot be converted to type 'System.Nullable`1[System.Int32] 使用反射从“System.Int32”到枚举的无效转换 - Invalid cast from 'System.Int32' to Enum using reflections 在枚举属性的情况下从 System.Int32 到 Nullable 的无效转换 - Invalid cast from System.Int32 to Nullable in case of Enum properties LINQ to Entities无法识别方法&#39;&lt;&gt; f__AnonymousType9`2 [System.Nullable`1 [System.Int32],System.Nullable` - LINQ to Entities does not recognize the method '<>f__AnonymousType9`2[System.Nullable`1[System.Int32],System.Nullable` JSON 值无法转换为 System.Nullable[System.Int32] - The JSON value could not be converted to System.Nullable[System.Int32] System.InvalidOperationException:从实例化的“ System.Int32”类型到可为空的“ Country”类型的指定强制转换无效 - System.InvalidOperationException: The specified cast from a materialized 'System.Int32' type to a nullable 'Country' type is not valid 代码优先迁移种子错误:未为类型&#39;System.Nullable&#39;1 [System.Int32]&#39;和&#39;System.Int32&#39;定义二进制运算符Equal - Code First Migration Seed Error: The binary operator Equal is not defined for the types 'System.Nullable`1[System.Int32]' and 'System.Int32' 类型&#39;System.Nullable`1 [System.Int32]&#39;的表达式不能用于类型&#39;System.Int32&#39;\\ r \\ n的构造函数参数名称:arguments [0] - Expression of type 'System.Nullable`1[System.Int32]' cannot be used for constructor parameter of type 'System.Int32'\r\nParameter name: arguments[0] 组合框中的 System.Int32[] - System.Int32[] in ComboBox LINQ:System.Int32是一个不可为空的值类型 - LINQ: System.Int32 is a non-nullable value type
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM