2012-11-07 89 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