2012-11-07 88 views
16

我們有一個類型爲long?的屬性,該屬性被填充爲int通過反射設置屬性時的類型轉換問題

這工作得很好,當我剛剛設置的屬性直接obj.Value = v;但是當我嘗試並設置通過反射info.SetValue(obj, v, null);屬性它給了我以下異常:

類型的對象「System.Int32」不能轉換爲類型'System.Nullable`1 [System.Int64]'。

這是一個簡化的情景:

class TestClass 
    { 
     public long? Value { get; set; } 
    } 

    [TestMethod] 
    public void TestMethod2() 
    { 
     TestClass obj = new TestClass(); 
     Type t = obj.GetType(); 

     PropertyInfo info = t.GetProperty("Value"); 
     int v = 1; 

     // This works 
     obj.Value = v; 

     // This does not work 
     info.SetValue(obj, v, null); 
    } 

爲什麼通過reflection設置屬性時,而它直接設置屬性時,它不工作?

回答

48

檢查爲文章全文:How to set value of a property using Reflection?

完整的代碼,如果你正在爲可空類型

public static void SetValue(object inputObject, string propertyName, object propertyVal) 
{ 
    //find out the type 
    Type type = inputObject.GetType(); 

    //get the property information based on the type 
    System.Reflection.PropertyInfo propertyInfo = type.GetProperty(propertyName); 

    //find the property type 
    Type propertyType = propertyInfo.PropertyType; 

    //Convert.ChangeType does not handle conversion to nullable types 
    //if the property type is nullable, we need to get the underlying type of the property 
    var targetType = IsNullableType(propertyInfo.PropertyType) ? Nullable.GetUnderlyingType(propertyInfo.PropertyType) : propertyInfo.PropertyType; 

    //Returns an System.Object with the specified System.Type and whose value is 
    //equivalent to the specified object. 
    propertyVal = Convert.ChangeType(propertyVal, targetType); 

    //Set the value of the property 
    propertyInfo.SetValue(inputObject, propertyVal, null); 

} 
private static bool IsNullableType(Type type) 
{ 
    return type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)); 
} 

需要值轉換這樣即需要值轉換爲您的屬性類型設定值像下面那樣

PropertyInfo info = t.GetProperty("Value"); 
object value = null; 
try 
{ 
    value = System.Convert.ChangeType(123, 
     Nullable.GetUnderlyingType(info.PropertyType)); 
} 
catch (InvalidCastException) 
{ 
    return; 
} 
propertyInfo.SetValue(obj, value, null); 

你需要這樣做是因爲你不能任意arbirtary值轉換爲給定類型...所以你需要將它轉換這樣

+0

優秀的答案! – series0ne

+0

對不起,延誤了你的代碼示例。這個伎倆,謝謝! – Shikyo

+0

設置'null'時不起作用。這很容易解決,試圖編輯你的文章,但被拒絕。 – Shikyo

2

當你寫:

obj.Value = v; 

編譯器知道如何做正確的鑄造,爲您和實際上編譯

obj.Value = new long?((long) v); 

當你使用反射沒有編譯器來幫助你。

2

因爲long類型具有隱式轉換方法。

6.1.2 Implicit numeric conversions

你可以看到隱式轉換方法存在的=符號背後隱藏的方法。

它也可空類型的工作:

int i = 0; 
int? j = i; // Implicit conversion 
long k = i; // Implicit conversion 
long? l = i; // Implicit conversion 

但去周圍的其他方法不起作用,因爲沒有隱式轉換存在一個null傳遞給非空:

int? i = 0; 
int j = i; // Compile assert. An explicit conversion exit... 
int k = (int)i; // Compile, but if i is null, you will assert at runtime. 

您不必將int明確轉換爲int? ...或long?

但是,當您使用反射時,您將繞過隱式轉換並直接將值分配給屬性。這樣,你必須明確地轉換它。

info.SetValue(obj, (long?)v, null); 

反射跳過所有隱藏在=背後的甜蜜東西。

+0

懷疑這樣的事情,謝謝你的明確解釋。 – Shikyo