C# 通过反射设置属性时的类型转换问题
我们有一个C# 通过反射设置属性时的类型转换问题,c#,reflection,C#,Reflection,我们有一个long?类型的属性,它用int填充 当我直接设置属性obj.Value=v时,这很好enum开始,让 //枚举对象负责此转换 如果(valueToSet!=null) { valueToSet=Enum.ToObject(targetType,valueToSet); } } 其他的 { //返回具有指定System.Type且其值为的System.Object //等效于指定的对象。 valueToSet=Convert.ChangeType(valueToSet,targetTy
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);
}
为什么通过反射设置属性时它不起作用,而直接设置属性时它起作用?查看全文:
如果您正在为可为null的类型设置值,则为完整代码
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<>));
}
您需要这样做,因为您无法将任何任意值转换为给定类型…因此您需要在编写以下内容时将其转换为如下所示:
obj.Value = v;
编译器知道如何为您执行正确的强制转换,并实际编译
obj.Value = new long?((long) v);
使用反射时,没有编译器可以帮助您。因为类型long
具有隐式转换方法
您可以将隐式转换方法视为存在于=
符号后面的隐藏方法
它也适用于可为空的类型:
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?
。。。或者一个长?
但是,当您使用反射时,您将绕过隐式转换并直接将值指定给属性。这样,您必须显式地转换它
info.SetValue(obj, (long?)v, null);
反思跳过所有隐藏在=
后面的甜言蜜语巩固和扩展的答案,以按照建议(和回答)处理枚举,并将累积的知识放在一个地方。这更容易复制/复制
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<>));
}
private void SetApiSettingValue(对象源、字符串属性名称、对象值设置)
{
//找出类型
Type Type=source.GetType();
//根据类型获取属性信息
System.Reflection.PropertyInfo property=type.GetProperty(propertyName);
//Convert.ChangeType不处理到可为空类型的转换
//如果属性类型可为null,则需要获取属性的基础类型
类型propertyType=property.propertyType;
var targetType=IsNullableType(propertyType)?Nullable.GetUnderlyingType(propertyType):propertyType;
//枚举的特殊情况
if(targetType.IsEnum)
{
//我们可以从int->enum开始,让
//枚举对象负责此转换
如果(valueToSet!=null)
{
valueToSet=Enum.ToObject(targetType,valueToSet);
}
}
其他的
{
//返回具有指定System.Type且其值为的System.Object
//等效于指定的对象。
valueToSet=Convert.ChangeType(valueToSet,targetType);
}
//设置属性的值
SetValue(source,valueToSet,null);
}
私有bool IsNullableType(类型)
{
返回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);
这就是如何做到这一点:
var newOne = Activator.CreateInstance(srcProp.GetType());
srcProp.SetValue(newGameData, newOne, null);
var newOne = Activator.CreateInstance(srcProp.PropertyType);
srcProp.SetValue(newGameData, newOne, null);
这是旧线。但此页面中的解决方案不起作用。我做了一些调整,效果很好(在.netcore2.0中)
obj=Activator.CreateInstance();
foreach(obj.GetType().GetProperties()中的PropertyInfo属性)
{
如果(!object.Equals(this.reader[prop.Name],DBNull.Value))
{
if(prop.PropertyType.Name.Contains(“Nullable”))
{
prop.SetValue(obj,Convert.ChangeType(this.reader[prop.Name],null.getUnderlineType(prop.PropertyType)),null);
}
其他的
{
prop.SetValue(obj,this.reader[prop.Name],null);
}
}
}
var properties=propTypes.GetProperty(属性)
TypeCode TypeCode=Type.GetTypeCode(properties.PropertyType)
很抱歉耽搁了,我把你的代码样本弄乱了。这就成功了,谢谢!设置“null”时,它不起作用。它很容易修复,尝试编辑您的帖子,但遭到拒绝。@PranayRana刚刚找到了这个解决方案,并将其应用到我遇到的一个问题中。工作得很好,我所做的唯一更改是将您的助手变成扩展。这在GUID上也有奇怪的中断。对于targetType,我使用这种方法:var targetType=Nullable.GetUnderlyingType(propType)??固有型;我怀疑是这样的,谢谢你的解释。我正在寻找如何转换为enum。谷歌把我带到这个页面,所以我很高兴你插话!!!工作起来很有魅力。
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;
}