remarks example cref c# reflection casting

example - remarks c#



''fundición'' con reflexión (5)

Considere el siguiente código de muestra:

class SampleClass { public long SomeProperty { get; set; } } public void SetValue(SampleClass instance, decimal value) { // value is of type decimal, but is in reality a natural number => cast instance.SomeProperty = (long)value; }

Ahora necesito hacer algo similar a través de la reflexión:

void SetValue(PropertyInfo info, object instance, object value) { // throws System.ArgumentException: Decimal can not be converted to Int64 info.SetValue(instance, value) }

Tenga en cuenta que no puedo suponer que PropertyInfo siempre represente un valor largo, ni que ese valor sea siempre un decimal. Sin embargo, sé que el valor se puede convertir al tipo correcto para esa propiedad.

¿Cómo puedo convertir el parámetro ''valor'' al tipo representado por la instancia PropertyInfo a través de la reflexión?


Aportando a la respuesta de jeroenh, agregaría que Convert.ChangeType se bloquea con un valor nulo, por lo que la línea para obtener el valor convertido debería ser:

var convertedValue = value == null ? null : Convert.ChangeType(value, targetType);


Cuando el Tipo es una Guía Nullable, ninguna de las soluciones propuestas anteriormente funciona. El lanzamiento inválido de la excepción '' System.DBNull '' a '' System.Guid '' se lanza a Convert.ChangeType

Para arreglar ese cambio a:

var convertedValue = value == System.DBNull.Value ? null : Convert.ChangeType(value, targetType);


La respuesta de Thomas es correcta, pero pensé que agregaría mi conclusión de que Convert.ChangeType no maneja la conversión a tipos anulables. Para manejar tipos anulables, utilicé el siguiente código:

void SetValue(PropertyInfo info, object instance, object value) { var targetType = info.PropertyType.IsNullableType() ? Nullable.GetUnderlyingType(info.PropertyType) : info.PropertyType; var convertedValue = Convert.ChangeType(value, targetType); info.SetValue(instance, convertedValue, null); }

Este código hace uso del siguiente método de extensión:

public static class TypeExtensions { public static bool IsNullableType(this Type type) { return type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)); }


La respuesta de Thomas solo funciona para los tipos que implementan la interfaz IConvertible:

Para que la conversión tenga éxito, el valor debe implementar la interfaz IConvertible, porque el método simplemente ajusta una llamada a un método IConvertible apropiado. El método requiere que se apoye la conversión de valor a conversionType.

Este código compila una expresión linq que realiza el desempaquetado (si es necesario) y la conversión:

public static object Cast(this Type Type, object data) { var DataParam = Expression.Parameter(typeof(object), "data"); var Body = Expression.Block(Expression.Convert(Expression.Convert(DataParam, data.GetType()), Type)); var Run = Expression.Lambda(Body, DataParam).Compile(); var ret = Run.DynamicInvoke(data); return ret; }

La expresión lambda resultante es igual a (TOut) (TIn) Datos donde TIn es el tipo de datos originales y TOut es el tipo dado


void SetValue(PropertyInfo info, object instance, object value) { info.SetValue(instance, Convert.ChangeType(value, info.PropertyType)); }