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