用reflection“铸造”
考虑下面的示例代码:
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总是表示一个长整型,而且这个值总是小数。 不过,我知道价值可以被铸造成属性的正确types。
如何通过reflection将“value”参数转换为由PropertyInfo实例表示的types?
void SetValue(PropertyInfo info, object instance, object value) { info.SetValue(instance, Convert.ChangeType(value, info.PropertyType)); }
托马斯的答案是正确的,但我想我会添加我的发现,Convert.ChangeType不处理转换为可空types。 为了处理可为空的types,我使用了下面的代码:
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接口的types:
为了转换成功,值必须实现IConvertible接口,因为该方法只是将调用包装为适当的IConvertible方法。 该方法要求支持将值转换为conversionType。
这段代码编译一个linqexpression式来完成拆箱(如果需要的话)和转换:
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; }
生成的lambdaexpression式等于(TOut)(TIn)Data其中TIn是原始数据的types,TOut是给定的types
贡献于jeroenh的答案,我会添加Convert.ChangeType崩溃与空值,所以得到转换后的值应该是:
var convertedValue = value == null ? null : Convert.ChangeType(value, targetType);
当types是可空导向时,上面提出的解决scheme都不起作用。 从“ System.DBNull
”到“ System.Guid
”exception的无效转换在Convert.ChangeType
引发
要将该更改修复为:
var convertedValue = value == System.DBNull.Value ? null : Convert.ChangeType(value, targetType);