2009-09-09 1 views
68

Рассмотрим следующий пример кода:«литье» с отражением

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; 
} 

Теперь мне нужно сделать что-то подобное с помощью отражения:

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

Следует заметить, что я не могу предположить, что PropertyInfo всегда представляет собой длинный , и это значение всегда является десятичным. Тем не менее, я знаю, что значение может быть присвоено правильному типу для этого свойства.

Как преобразовать параметр «значение» в тип, представленный экземпляром PropertyInfo, посредством отражения?

ответ

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

Ответ Томаса является правильным, но я думал, что я хотел бы добавить мой вывод, что Convert.ChangeType не обрабатывает преобразование в обнуляемые тип. Для обработки обнуляемых типов, я использовал следующий код:

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); 
} 

Этот код использует следующий метод расширения:

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

это сработало для меня, очень четкое объяснение, спасибо –

9

Содействие в ответ jeroenh, я хотел бы добавить, что Convert.ChangeType аварии с микросхемой нулевое значение, поэтому линия для получения преобразованного значения должны быть:

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

Я собирался опубликовать это! –

1

Когда тип является Nullable Guid, то ни один из предложенных выше решений работы. Invalid бросок от «System.DBNull» до «System.Guid» исключение выбрасывается в Convert.ChangeType

Чтобы исправить это изменение:

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

Эта проблема не специфична для Guid, а скорее из-за того, что вы получаете 'DBNull.Value' вместо просто' null' при извлечении нулевых значений из базы данных через ADO.Net. Например, вы увидите то же самое с обнуляемым int. – jeroenh

28

Томас ответ работает только для типов, реализующих IConvertible интерфейс:

Чтобы преобразование было успешным, значение должно реализовать интерфейс IConvertible, потому что метод просто обертывает вызов соответствующему методу IConvertible. Для этого метода требуется преобразование значения в тип преобразования.

Этот код составить выражение Linq, который делает распаковку (если это необходимо) и преобразование:

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; 
    } 

Полученная лямбда-выражение равно (Tout) (TiN) данным, где олово типа исходные данные и TOUT - данный тип

+1

Это на самом деле ответ, который я искал. Неконтактное динамическое литье. – jnm2

+0

Вы можете отметить это как принято :) – rafael

+1

Хех я бы ... если бы я был ОП. – jnm2

 Смежные вопросы

  • Нет связанных вопросов^_^