Ошибка преобразования типа при настройке свойства путем отражения
У нас есть свойство типа long?
, которое заполняется с помощью int
.
Это отлично работает, когда я просто устанавливаю свойство непосредственно obj.Value = v;
, но когда я пытаюсь установить свойство через отражение info.SetValue(obj, v, null);
, это дает мне следующее исключение:
Объект типа 'System.Int32' не может быть преобразован в тип 'System.Nullable`1 [System.Int64]'.
Это упрощенный сценарий:
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);
}
Почему он не работает при настройке свойства через reflection
, когда он работает при настройке свойства напрямую?
Ответы
Ответ 1
Проверить полную статью: Как установить значение свойства с помощью Reflection?
полный код, если вы устанавливаете значение для типа NULL
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(propertyInfo.PropertyType) ? Nullable.GetUnderlyingType(propertyInfo.PropertyType) : propertyInfo.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<>));
}
вам нужно преобразовать значение, подобное этому. i.e вам нужно преобразовать значение в свой тип свойства, как показано ниже
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);
вам нужно сделать это, потому что вы не можете преобразовать какое-либо арбилярное значение в заданный тип... так что вам нужно преобразовать его так:
Ответ 2
Когда вы пишете:
obj.Value = v;
компилятор знает, как сделать правильное кастинг для вас и фактически компилирует
obj.Value = new long?((long) v);
Когда ваше отражение использования не содержит компилятора.
Ответ 3
Поскольку тип long
имеет неявный метод преобразования.
6.1.2 Неявные числовые преобразования
Вы можете увидеть неявный метод преобразования как скрытый метод, который существует за символом =
.
Он также работает с типом NULL:
int i = 0;
int? j = i; // Implicit conversion
long k = i; // Implicit conversion
long? l = i; // Implicit conversion
Но движение в другую сторону не работает, потому что не существует никакого неявного преобразования, чтобы передать значение null
в значение, отличное от нуля:
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.
Вам не нужно явно преобразовывать a int
в int?
... или long?
.
Однако, когда вы используете отражение, вы обходите неявное преобразование и напрямую присваиваете значение свойству. Таким образом, вы должны его явно преобразовать.
info.SetValue(obj, (long?)v, null);
Отражение пропускает все сладкие вещи, скрытые за =
.