Saltar al contenido

Conversión no válida de ‘System.Int32’ a ‘System.Nullable`1[[System.Int32, mscorlib]]

Si encuentras algún fallo en tu código o proyecto, recuerda probar siempre en un entorno de testing antes aplicar el código al trabajo final.

Solución:

tienes que usar Nullable.GetUnderlyingType para obtener el tipo subyacente de Nullable.

Este es el método que utilizo para superar la limitación de ChangeType por Nullable

public static T ChangeType(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);

método no genérico:

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

Para arriba, simplemente podría escribir int? nVal = valor

En realidad, tampoco puedes hacer eso. No hay conversión implícita de object para Nullable. Pero hay es una conversión implícita de int para Nullable para que puedas escribir esto:

int? unVal = (int)val;

Puedes usar Nullable.GetUnderlyingType método.

Devuelve el argumento de tipo subyacente del tipo que acepta valores NULL especificado.

Una definición de tipo genérico es una declaración de tipo, como Nullable, que contiene una lista de parámetros de tipo y la lista de parámetros de tipo declara uno o más parámetros de tipo. Un tipo genérico cerrado es una declaración de tipo donde se especifica un tipo particular para un parámetro de tipo.

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

Aquí está un DEMO.

Creo que debería explicar por qué la función no funciona:

1- La línea que arroja la excepción es la siguiente:

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

de hecho, la función de búsqueda en el array Convert.ConvertTypes después de eso, ve si el objetivo es un Enum y cuando no se encuentra nada, lanza la excepción anterior.

2- Convert.ConvertTypes se inicializa como:

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

Así que desde el int? no está en ConvertTypes array y no un Enum, se lanza la excepción.

Entonces, para resumir, para que la función Convert.ChnageType funcione, tiene:

  1. El objeto a convertir es IConvertible

  2. El tipo de destino está dentro de ConvertTypes y no Empty ni DBNull (Hay una prueba explícita en esos dos con excepción de lanzamiento)

Este comportamiento se debe a que int (y todos los demás tipos predeterminados) utiliza Convert.DefaultToType como IConvertibale.ToType implementation. and here is the code of thePredeterminado a tipoextracted utilizando 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
    ));

por otro lado, la conversión se implementa mediante la propia clase Nullable y la definición es:

public static implicit operator T?(T value)

    return new T?(value);

public static explicit operator T(T? value)

    return value.Value;

Puntuaciones y comentarios

Si te mola el proyecto, tienes la opción de dejar una reseña acerca de qué te ha parecido esta división.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *