通过反射设置属性值不起作用,而直接在 C 中设置属性值#

Setting property value via reflection doesn't work while setting it directly works in C#

提问人:user2653422 提问时间:6/6/2023 更新时间:6/6/2023 访问量:93

问:

我正在尝试通过 C# 中的反射来设置框架类型的属性的值。 该物业似乎是双打的容器,用单位丰富了双打。TargetPropTargetPropType

做以下工作

parentOfProperty.TargetProp = 5.0;

虽然以下操作失败,但出现 System.ArgumentException:“'System.Double' 类型的对象无法转换为'TargetPropType' 类型。

PropertyInfo setProperty = parentOfProperty.GetType().GetProperty("TargetProp");
setProperty.SetValue(parentOfProperty, 5.0, null);

以下操作也会失败,并出现相同的异常

setProperty.GetSetMethod()?.Invoke(parentOfProperty, new object[] { 5.0 });

在反射分配失败时,它的第一个分配会有什么不同?

C# 异常 反射 强制转换 属性

评论

1赞 Sweeper 6/6/2023
请出示声明并提供最小的可重复示例TargetProp
0赞 Mong Zhu 6/6/2023
你写“TargetPropType类型”隐式强制转换运算符是否被覆盖?
0赞 user2653422 6/6/2023
@Sweeper 信息可以在这里找到。我不知道如何生成一个最小的可重复示例,如果该框架是付费的,可能只有极少数人可以访问。TargetProp
0赞 user2653422 6/6/2023
@MongZhu 不,没有任何变化。它直接在框架之外使用。TargetProp
2赞 Sweeper 6/6/2023
没有方便的方法可以做到这一点。你可以保留一个,告诉你如何创建每种可能的类型。Dictionary<Type, Func<object, object>>TaregtProp

答:

2赞 Sweeper 6/6/2023 #1

将属性直接设置为有效,但使用反射则无效,因为属性的类型具有隐式转换,如您在注释中链接的那样。反射不会解析隐式转换运算符。doubleint

因此,您只需手动调用隐式转换运算符,并将结果传递给:SetValue

TargetPropType arg = 5.0;
setProperty.SetValue(parentOfProperty, arg, null);

但是,您似乎想要一个更通用的解决方案。从评论:

该程序读取输入文件和转换文件。由转换文件提供,可以是框架中的任何属性。在运行时,程序只知道某些值必须转换为 。TargetPropTargetProp

我建议使用 a 来准确记录如何创建您可能遇到的每种类型的属性。我们称之为 .例如,将有一个条目,其中键为 ,值如下所示:Dictionary<Type, Func<object, object>>conversionsDictconversionsDicttypeof(TargetPropType)

o => {
    TargetPropType result = (double)o; // assuming only doubles can get converted to TargetPropType
    return result;
    // or simply "return new TargetPropType((double)o)" if that's what the implicit conversion does
}

您可以将所有需要转换的类型放入 中,然后执行以下操作:conversionsDict

PropertyInfo setProperty = parentOfProperty.GetType().GetProperty(someStringYouGetFromTransformationFile);
Type propertyType = setProperty.PropertyType;
object value = theValueYouWantToSet;
if (conversionsDict.TryGetValue(propertyType, out var converter)) {
    value = converter(value);
}
setProperty.SetValue(parentOfProperty, value, null);

或者,您可以使用反射来调用隐式转换运算符。该运算符编译为 IL 中名为 的方法,尽管我不确定是否在任何地方指定了这种方法。op_Implicit

// list out the primitive types that needs no conversion
var listOfPrimitives = new List<Type>() { ... };
object value = theValueYouWantToSet;
if (!listOfPrimitives.Contains(propertyType)) {
    var method = propertyType.GetMethod("op_Implicit", new[] { value.GetType() });
    if (method != null) {
        value = method.Invoke(null, new[] { value });
    }
}
setProperty.SetValue(parentOfProperty, value, null);

另请参阅这篇使用 API 的帖子TypeDescriptor

评论

0赞 user2653422 6/6/2023
非常感谢,我使用了您提供的替代方法,该方法适用于我的情况。