c# - tabla - Tipo de problema de conversión al configurar la propiedad a través de la reflexión
problemas de kilogramos para quinto de primaria (5)
Consolidar y expandir la respuesta de para manejar las enum
sugeridas por SilverNinja (y respondidas por thecoop ) y colocar los aprendizajes acumulados en un solo lugar. Esto es un poco más de copia / pastable .;
private void SetApiSettingValue(object source, string propertyName, object valueToSet)
{
// find out the type
Type type = source.GetType();
// get the property information based on the type
System.Reflection.PropertyInfo property = type.GetProperty(propertyName);
// Convert.ChangeType does not handle conversion to nullable types
// if the property type is nullable, we need to get the underlying type of the property
Type propertyType = property.PropertyType;
var targetType = IsNullableType(propertyType) ? Nullable.GetUnderlyingType(propertyType) : propertyType;
// special case for enums
if (targetType.IsEnum)
{
// we could be going from an int -> enum so specifically let
// the Enum object take care of this conversion
if (valueToSet != null)
{
valueToSet = Enum.ToObject(targetType, valueToSet);
}
}
else
{
// returns an System.Object with the specified System.Type and whose value is
// equivalent to the specified object.
valueToSet = Convert.ChangeType(valueToSet, targetType);
}
// set the value of the property
property.SetValue(source, valueToSet, null);
}
private bool IsNullableType(Type type)
{
return type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>));
}
Tenemos una propiedad de tipo long?
que se llena con un int
.
Esto funciona bien cuando acabo de establecer la propiedad directamente obj.Value = v;
pero cuando intento establecer la propiedad a través de la reflexión info.SetValue(obj, v, null);
me da la siguiente excepción:
El objeto de tipo ''System.Int32'' no se puede convertir al tipo ''System.Nullable`1 [System.Int64]''.
Este es un escenario simplificado:
class TestClass
{
public long? Value { get; set; }
}
[TestMethod]
public void TestMethod2()
{
TestClass obj = new TestClass();
Type t = obj.GetType();
PropertyInfo info = t.GetProperty("Value");
int v = 1;
// This works
obj.Value = v;
// This does not work
info.SetValue(obj, v, null);
}
¿Por qué no funciona al configurar la propiedad a través de la reflection
mientras funciona al configurar la propiedad directamente?
Cuando escribes:
obj.Value = v;
el compilador sabe cómo hacer el casting adecuado para usted y compila realmente
obj.Value = new long?((long) v);
Cuando usas la reflexión no hay compilador para ayudarte.
Porque el tipo long
tiene un método de conversión implícito.
6.1.2 Conversiones numéricas implícitas
Puede ver el método de conversión implícito como método oculto que existe detrás del símbolo =
.
También funciona con tipo nullable:
int i = 0;
int? j = i; // Implicit conversion
long k = i; // Implicit conversion
long? l = i; // Implicit conversion
Pero ir al revés no funciona, porque no existe una conversión implícita para pasar un null
a un no nulo:
int? i = 0;
int j = i; // Compile assert. An explicit conversion exit...
int k = (int)i; // Compile, but if i is null, you will assert at runtime.
¿No tienes que convertir explícitamente un int
en un int?
... o un long?
.
Sin embargo, cuando utiliza la reflexión, está omitiendo la conversión implícita y asigna directamente el valor a la propiedad. De esta manera, hay que convertirlo explícitamente.
info.SetValue(obj, (long?)v, null);
La reflexión salta todas las cosas dulces escondidas detrás =
.
También me encontré con este problema al crear nuevos objetos reflexivamente.
Así es como no hacerlo:
var newOne = Activator.CreateInstance(srcProp.GetType());
srcProp.SetValue(newGameData, newOne, null);
Y así es como se hace:
var newOne = Activator.CreateInstance(srcProp.PropertyType);
srcProp.SetValue(newGameData, newOne, null);
Ver el artículo completo: ¿Cómo establecer el valor de una propiedad utilizando Reflection?
código completo si está configurando el valor para el tipo anulable
public static void SetValue(object inputObject, string propertyName, object propertyVal)
{
//find out the type
Type type = inputObject.GetType();
//get the property information based on the type
System.Reflection.PropertyInfo propertyInfo = type.GetProperty(propertyName);
//find the property type
Type propertyType = propertyInfo.PropertyType;
//Convert.ChangeType does not handle conversion to nullable types
//if the property type is nullable, we need to get the underlying type of the property
var targetType = IsNullableType(propertyType) ? Nullable.GetUnderlyingType(propertyType) : propertyType;
//Returns an System.Object with the specified System.Type and whose value is
//equivalent to the specified object.
propertyVal = Convert.ChangeType(propertyVal, targetType);
//Set the value of the property
propertyInfo.SetValue(inputObject, propertyVal, null);
}
private static bool IsNullableType(Type type)
{
return type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>));
}
necesita convertir valor como este, es decir, debe convertir valor a su tipo de propiedad como se muestra a continuación
PropertyInfo info = t.GetProperty("Value");
object value = null;
try
{
value = System.Convert.ChangeType(123,
Nullable.GetUnderlyingType(info.PropertyType));
}
catch (InvalidCastException)
{
return;
}
propertyInfo.SetValue(obj, value, null);
necesita hacer esto porque no puede convertir ningún valor arbirario al tipo dado ... así que necesita convertirlo así