Ответ 1
void SetValue(PropertyInfo info, object instance, object value)
{
info.SetValue(instance, Convert.ChangeType(value, info.PropertyType));
}
Рассмотрим следующий пример кода:
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, через отражение?
void SetValue(PropertyInfo info, object instance, object value)
{
info.SetValue(instance, Convert.ChangeType(value, info.PropertyType));
}
Ответ Томаса прав, но я думал, что добавлю, что 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<>));
}
Томас отвечает только на типы, реализующие интерфейс 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) данных, где TIn - тип исходных данных, а TOUT - заданный тип
В ответ на jeroenh answer я добавлю, что Convert.ChangeType вылетает с нулевым значением, поэтому строка для получения преобразованного значения должна быть:
var convertedValue = value == null ? null : Convert.ChangeType(value, targetType);
Когда Тип является Nullable Guid, ни одно из вышеперечисленных предлагаемых решений не работает.
Недопустимый сброс из 'System.DBNull
' в 'System.Guid
' исключение выбрано в Convert.ChangeType
Чтобы исправить это изменение:
var convertedValue = value == System.DBNull.Value ? null : Convert.ChangeType(value, targetType);
Это очень старый вопрос, но я решил присоединиться к ASP.NET Core Googlers.
В ASP.NET Core .IsNullableType()
защищен (среди других изменений), поэтому код немного отличается. Вот ответ @jeroenh, модифицированный для работы в ASP.NET Core:
void SetValue(PropertyInfo info, object instance, object value)
{
Type proptype = info.PropertyType;
if (proptype.IsGenericType && proptype.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
proptype = new NullableConverter(info.PropertyType).UnderlyingType;
}
var convertedValue = Convert.ChangeType(value, proptype);
info.SetValue(instance, convertedValue);
}