我们有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
设置属性时它不起作用?
答案 0 :(得分:62)
查看完整文章: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(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值转换为给定的类型......所以你需要像这样转换它
答案 1 :(得分:3)
当你写:
obj.Value = v;
编译器知道如何为您进行正确的转换并实际编译
obj.Value = new long?((long) v);
当您使用反射时,没有编译器可以帮助您。
答案 2 :(得分: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
传递给非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);
反思会跳过隐藏在=
后面的所有甜蜜的东西。
答案 3 :(得分:0)
根据Pranay Rana的建议(并SilverNinja回答)整合并扩展thecoop处理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<>));
}
答案 4 :(得分:0)
反射性地创建新对象时,我也遇到了这个问题。
这是不这样做的方法:
var newOne = Activator.CreateInstance(srcProp.GetType());
srcProp.SetValue(newGameData, newOne, null);
这是方法:
var newOne = Activator.CreateInstance(srcProp.PropertyType);
srcProp.SetValue(newGameData, newOne, null);
答案 5 :(得分:0)
这是旧线程。但是此页面中的解决方案不起作用。我做了一些调整,效果很好(在.netcore 2.0中)!
obj = Activator.CreateInstance<T>();
foreach (PropertyInfo prop in obj.GetType().GetProperties())
{
if (!object.Equals(this.reader[prop.Name], DBNull.Value))
{
if (prop.PropertyType.Name.Contains("Nullable"))
{
prop.SetValue(obj, Convert.ChangeType(this.reader[prop.Name], Nullable.GetUnderlyingType(prop.PropertyType)), null);
}
else
{
prop.SetValue(obj, this.reader[prop.Name], null);
}
}
}
答案 6 :(得分:0)
var 属性 = propTypes.GetProperty(attribute);
TypeCode typeCode = Type.GetTypeCode(properties.PropertyType);
switch (typeCode)
{
case TypeCode.Int32:
properties.SetValue(m, Convert.ToInt32(value.AsPrimitive().Value));
break;
case TypeCode.Int64:
properties.SetValue(m, Convert.ToInt64(value.AsPrimitive().Value));
break;
}