Ошибка преобразования типа при настройке свойства путем отражения

У нас есть свойство типа 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);

Отражение пропускает все сладкие вещи, скрытые за =.