通过reflection设置属性时键入转换问题
我们有一个long?
类型的属性long?
充满了int
。
当我直接设置属性obj.Value = v;
时,这工作正常obj.Value = v;
但是当我尝试通过reflection信息设置属性时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
设置属性时不起作用?
查看全文: 如何使用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(propertyType) ? Nullable.GetUnderlyingType(propertyType) : 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值转换为给定类型…所以你需要像这样转换它
当你写:
obj.Value = v;
编译器知道如何为您进行正确的转换并实际编译
obj.Value = new long?((long) v);
当您使用reflection时,没有编译器可以帮助您。
因为long
类型有一个隐式转换方法。
6.1.2隐式数字转换
您可以将隐式转换方法视为=
符号后面的隐藏方法。
它也适用于可空类型:
int i = 0; int? j = i; // Implicit conversion long k = i; // Implicit conversion long? l = i; // Implicit conversion
但是反过来不起作用,因为没有隐式转换将null
传递给非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?
。
但是,当您使用reflection时,您将绕过隐式转换并直接将值分配给属性。 这样,您必须明确地转换它。
info.SetValue(obj, (long?)v, null);
reflection跳过隐藏在背后的所有甜蜜的东西=
。
根据SilverNinja (并由thecoop回答)建议,巩固和扩展Pranay Rana处理enum
的答案,并将学习积累在一个地方。 这是一个更复制/可爱的。
private void SetApiSettingValue(object source, string propertyName, object valueToSet) { // find out the type Type type = source.GetType(); // get the property information based on the type System.Reflection.PropertyInfo property = type.GetProperty(propertyName); // 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 Type propertyType = property.PropertyType; var targetType = IsNullableType(propertyType) ? Nullable.GetUnderlyingType(propertyType) : propertyType; // special case for enums if (targetType.IsEnum) { // we could be going from an int -> enum so specifically let // the Enum object take care of this conversion if (valueToSet != null) { valueToSet = Enum.ToObject(targetType, valueToSet); } } else { // returns an System.Object with the specified System.Type and whose value is // equivalent to the specified object. valueToSet = Convert.ChangeType(valueToSet, targetType); } // set the value of the property property.SetValue(source, valueToSet, null); } private bool IsNullableType(Type type) { return type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)); }
在reflection创建新对象时,我也遇到了这个问题。
这是不怎么做:
var newOne = Activator.CreateInstance(srcProp.GetType()); srcProp.SetValue(newGameData, newOne, null);
这是怎么做的:
var newOne = Activator.CreateInstance(srcProp.PropertyType); srcProp.SetValue(newGameData, newOne, null);