que tienen algo de código (que funciona bien) que se ve algo como esto:¿Cómo puedo usar la reflexión para convertir de int a decimal?
int integer = 42;
decimal? castTo = integer;
luego quería hacer algo similar con la reflexión, con algo de código que tiene este aspecto:
object value = source; // source was an int originally
var parameters = new object[1];
...
parameters[0] = value;
var setMethod = property.GetSetMethod();
// Call the set method, which takes a decimal? as a parameter
setMethod.Invoke(o, parameters);
Cuando Hago esto, obtengo:
failed: System.ArgumentException : Object of type 'System.Int32' cannot be converted to type 'System.Nullable`1[System.Decimal]'.
at System.RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
¿Por qué una conversión de tipo implícito que funciona bien en otro lugar falla con la reflexión? ¿Hay algún truco para usar la reflexión para realizar esta conversión?
Editar: Gracias a todos por las respuestas. Aquí está la solución que se me ocurrió, sobre la base de las respuestas:
private object Convert(object source, Type destinationType)
{
if (source == null)
{
return null;
}
var sourceType = source.GetType();
// unwrap nullable types
var nullableType = Nullable.GetUnderlyingType(destinationType);
if(nullableType != null)
{
destinationType = nullableType;
}
nullableType = Nullable.GetUnderlyingType(sourceType);
if(nullableType != null)
{
sourceType = nullableType;
}
var implicitCastMethod =
destinationType.GetMethod("op_Implicit",
new[] { sourceType });
if(implicitCastMethod == null)
{
return null;
}
return implicitCastMethod.Invoke(null, new[] { source });
}
Edición # 2: Me gustaría que alguien había mencionado System.Convert.ChangeType()
, que se ocupa de estos casos, y más. Resulta que op_Implicit
solo puede convertir a tipos numéricos menos restrictivos. (por supuesto, de ahí el "implícito" en el nombre). En otras palabras, la primera solución funcionó para int
→ decimal?
pero no decimal?
→ int
. (Parece que necesitaría para cambiar el código de probar también op_Explicit
si la conversión implícita falló, si quería ser capaz de manejar una conversión de decimal?
de nuevo a int
.)
Desde System.Convert.ChangeType()
no funciona con Nullable<>
tipos, que finalmente acabaron utilizando un código similar a lo que he encontrado here (ligeramente modificada):
private static object Convert(object source, Type destinationType)
{
if(destinationType == null)
{
throw new ArgumentNullException("destinationType");
}
if(destinationType.IsGenericType &&
destinationType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
if (source == null)
{
return null;
}
destinationType = Nullable.GetUnderlyingType(destinationType);
}
return System.Convert.ChangeType(source, destinationType);
}
Esto es esencialmente lo que funcionó para mí. Al menos me puso en el camino correcto. ¡Gracias! – mpontillo
'MethodInfo method = source.GetType(). GetMethod (" op_Implicit ");' es más fácil de leer que la búsqueda en bucle explícita. –
@Merlyn, sí, notará que eso es lo que hice si lee mi primera edición, excepto que también agregué el tipo en la llamada GetMethod() también. De lo contrario, si hubiera varios métodos op_Implicit sobrecargados, creo que todavía tendría que hacer un bucle? – mpontillo