c# - property - Conversión inválida de ''System.Int32'' a ''System.Nullable`1[
propiedad nullable c# (3)
Para arriba simplemente podría escribir int? nVal = val
En realidad, tampoco puedes hacer eso. No hay conversión implícita de object
a Nullable<int>
. Pero hay una conversión implícita de int
a Nullable<int>
para que pueda escribir esto:
int? unVal = (int)val;
Puede usar el método Nullable.GetUnderlyingType
.
Devuelve el argumento de tipo subyacente del tipo anulable 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í una DEMO
.
Type t = typeof(int?); //will get this dynamically
object val = 5; //will get this dynamically
object nVal = Convert.ChangeType(val, t);//getting exception here
Estoy obteniendo InvalidCastException en el código anterior. Para arriba simplemente podría escribir int? nVal = val
int? nVal = val
, pero el código anterior se está ejecutando dinámicamente.
Obtengo un valor (de tipo no anulable como int, float, etc.) envuelto en un objeto (aquí val), y tengo que guardarlo en otro objeto al convertirlo a otro tipo (que puede o no ser una versión que admite nulos) de eso). Cuando
Conversión inválida de ''System.Int32'' a ''System.Nullable`1 [[System.Int32, mscorlib, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089]]''.
Un int
, debe ser convertible / type-convertible a nullable int
, ¿cuál es el problema aquí?
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 la matriz Convert.ConvertTypes después de eso, ve si el targer es un Enum y cuando no se encuentra nada arroja 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)
};
Entonces desde el int?
no está en la matriz ConvertTypes y no hay un Enum. Se lanza la excepción.
Entonces, para reanudar, para que la función Convert.ChnageType funcione, tiene:
El objeto a convertir es IConvertible
El tipo de destino está dentro de ConvertTypes y no está
Empty
niDBNull
(hay una prueba de expulsión en esos dos con excepción de lanzamiento)
Este comportamiento se debe a que int
(y todos los demás tipos predeterminados) utiliza la implementation. and here is the code of the
Convert.DefaultToType
como IConvertibale.ToType implementation. and here is the code of the
implementation. and here is the code of the
DefaultToType extracted
usando 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, el elenco está implementado por la 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;
}
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
for 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);
}
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);
}