2009-09-09 68 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

这个工作对我来说,很清楚的解释,谢谢 – 2017-11-10 01:13:48

9

特约jeroenh的答案,我想补充一个是Convert.ChangeType崩溃空值,所以获得转换值的行应该是:

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

我正要张贴此! – 2012-11-12 12:08:41

1

当Type是可空导引符时,以上提出的解决方案都不起作用。 从 'System.DBNull' 无效的转换为 'System.Guid' 例外在Convert.ChangeType

抛出要解决这个修改:

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

这个问题并不是Guid所特有的,而是因为当通过ADO.Net从数据库中获取空值时,你得到'DBNull.Value'而不是'null'。例如,您将看到与可空int相同的内容。 – jeroenh 2013-02-27 10:27:20

28

托马斯回答只适用于实现IConvertible接口类型:

为了转换成功,值必须实现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; 
    } 

所得lambda表达式等于(TOUT)(锡)数据,其中锡的类型原始数据和吹捧是给定类型

+1

这实际上是我寻找的答案。非集成动态铸造。 – jnm2 2015-01-22 21:27:40

+0

你可以把它标记为接受:) – rafael 2015-01-23 00:25:26

+1

嘿,我会 - 如果我是OP。 – jnm2 2015-01-23 00:37:36