You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过表达式获取属性自定义属性时的继承问题排查

问题原因与解决方案

你遇到的这个问题其实是表达式树的编译时解析特性导致的,并不是你的操作有误,我来给你详细解释并提供可行的解决办法:

为什么输出两次“Base”?

当你编写(Derived data) => data.Code这样的表达式时,虽然Code是Derived重写的属性,但在编译阶段,编译器会把这个成员引用解析到基类Base的Code属性上——因为重写的成员在编译时的符号仍然指向基类的定义,表达式树构建的是编译时的成员信息,而非运行时的实际实现。所以不管你用Derived还是Base作为表达式的输入类型,最终拿到的MemberExpression都是指向Base.Code,自然获取到的是基类上的XmlElement("Base")特性。

你注释里的反射代码能拿到正确结果,是因为typeof(Derived).GetProperty(nameof(Derived.Code))是直接从Derived类型的元数据中查找属性,会正确定位到派生类的重写属性,所以能获取到XmlElement("Derived")特性。

如何通过表达式获取派生类的自定义属性?

你可以修改Write方法,结合泛型参数的实际类型来获取属性,而不是直接从表达式的Member中取。这样就能拿到对应类型上的属性特性:

private static void Write<T1,T2>(Expression<Func<T1,T2>> expression) {
    // 1. 获取泛型参数T1的实际类型(比如Derived)
    var targetType = typeof(T1);
    // 2. 从表达式中提取属性名称
    var propertyName = ((MemberExpression)expression.Body).Member.Name;
    // 3. 从目标类型中获取对应的属性(会优先取派生类的重写属性)
    var targetProperty = targetType.GetProperty(propertyName);
    // 4. 获取属性上的自定义特性
    Console.WriteLine(targetProperty.GetCustomAttribute<XmlElementAttribute>().ElementName);
}

修改后再运行你的代码,输出就会是:

Derived
Base

额外说明

如果你的场景中,表达式的输入类型是Base但实际运行时实例是Derived,这种情况仅通过表达式树无法直接获取派生类的特性,因为表达式树是编译时确定的。这时候你需要结合运行时实例的类型来获取属性,比如把实例也作为参数传入方法中。不过在你的当前代码结构里,上面的方案已经完全满足需求啦。

内容的提问来源于stack exchange,提问作者wpfwannabe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:12:13