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