我们有类型的属性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
而它直接设置属性时?
查看全文: 如何设置使用反射属性的值?
完整的代码,如果你正在为可空类型值
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);
当您使用反射没有编译器来帮助你。
因为类型long
有一个隐式转换方法。
6.1.2隐式数值转换
你可以看到隐式转换方法存在的背后隐藏方法=
符号。
它也可空类型的工作:
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);
反射跳过所有甜的东西背后隐藏的=
。
巩固和扩大Pranay蛙的回答来处理enum
S按所建议SilverNinja (并回答thecoop ),并把在一个地方积累的学习收获。 这是一个多一点的副本/ pastable;
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<>));
}
反射性地创建新的对象时,我也遇到了这个问题。
这是多么不这样做:
var newOne = Activator.CreateInstance(srcProp.GetType());
srcProp.SetValue(newGameData, newOne, null);
这是如何做到这一点:
var newOne = Activator.CreateInstance(srcProp.PropertyType);
srcProp.SetValue(newGameData, newOne, null);