jer*_*enh 76 c# reflection casting
请考虑以下示例代码:
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;
}
Run Code Online (Sandbox Code Playgroud)
现在我需要通过反思来做类似的事情:
void SetValue(PropertyInfo info, object instance, object value)
{
// throws System.ArgumentException: Decimal can not be converted to Int64
info.SetValue(instance, value)
}
Run Code Online (Sandbox Code Playgroud)
请注意,我不能假设PropertyInfo总是表示long,而且该值始终不是小数.但是,我知道可以将值转换为该属性的正确类型.
如何通过反射将'value'参数转换为PropertyInfo实例表示的类型?
Tho*_*que 127
void SetValue(PropertyInfo info, object instance, object value)
{
info.SetValue(instance, Convert.ChangeType(value, info.PropertyType));
}
Run Code Online (Sandbox Code Playgroud)
jer*_*enh 39
Thomas的答案是对的,但我想我会发现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);
}
Run Code Online (Sandbox Code Playgroud)
此代码使用以下扩展方法:
public static class TypeExtensions
{
public static bool IsNullableType(this Type type)
{
return type.IsGenericType
&& type.GetGenericTypeDefinition().Equals(typeof(Nullable<>));
}
Run Code Online (Sandbox Code Playgroud)
Raf*_*ael 37
托马斯答案仅适用于实现IConvertible接口的类型:
要使转换成功,value必须实现IConvertible接口,因为该方法只是调用适当的IConvertible方法.该方法要求支持将值转换为conversionType.
此代码编译一个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;
}
Run Code Online (Sandbox Code Playgroud)
得到的lambda表达式等于(TOut)(TIn)数据,其中TIn是原始数据的类型,TOut是给定类型
Ign*_*lvo 10
有助于jeroenh的回答,我想补充说Convert.ChangeType崩溃时为空值,因此获取转换值的行应为:
var convertedValue = value == null ? null : Convert.ChangeType(value, targetType);
Run Code Online (Sandbox Code Playgroud)