【问题标题】:LambdaExpression gets incorrect DeclaringType for overriden propertyLambdaExpression 为覆盖的属性获取不正确的 DeclaringType
【发布时间】:2018-11-27 16:25:29
【问题描述】:

我有以下课程:

public class Foo
{
    public virtual string FooProperty { get; set; }
}
public class Bar : Foo
{
    public override string FooProperty { get => base.FooProperty; set => base.FooProperty = value; }
}

我定义了一个 lambda 表达式:

Expression<Func<Bar, string>> expression = (Bar b) => b.FooProperty;

当我检查 MemberExpression 的 DeclaringType 时,我得到的类型是 Foo 而不是 Bar,就像我预期的那样。这是为什么呢?

var type = (expression.Body as MemberExpression).Member.DeclaringType;   // returns Foo type

【问题讨论】:

    标签: c# linq lambda expression


    【解决方案1】:

    所以这是一个棘手的问题。从技术上讲,Bar 声明了一个属性,该属性称为FooProperty。我们可以通过获取BarType 来查看这一点,获取它的FooProperty 信息并打印its 声明类型。

    var prop = typeof(Bar).GetProperty("FooProperty");
    Console.WriteLine(prop.DeclaringType);
    

    那个将打印出Bar,而不是Foo。所以Bar 声明了一个属性,但是,您显示的代码导致Foo 的原因是FooBar 都声明了一个名为FooProperty 的属性,但是在调用站点它实际上并没有调用Bar.FooProperty,它调用基类型的版本并让虚拟调度句柄确保Bar 声明的属性是实际执行的两个声明的属性特性。这意味着 被调用的属性的声明类型 (当您从表达式中获取成员信息时,您正在计算的内容,而不是像我上面所做的那样从导航类型)是Foo,尽管这两种类型都声明了一个名为 FooProperty 的属性。

    【讨论】:

    • 谢谢!我真正想要实现的是检查我仅在Bar.FooProperty 上专门声明的属性的自定义属性。猜猜我必须从 lambda 表达式的参数中获取 PropertyInfo 的类型。
    • @TorbjörnHansson 请记住,如果实际传入的对象是 Bar 的派生类型,其属性的值与 Bar 声明该方法的属性值不同,那么您不会看到实际执行的版本的属性。 (如果您想防止这种情况发生,可以将Bar 的声明标记为sealed。)
    • 好点。这次我只使用表达式作为配置,所以我不会实际编译和调用它们。
    • 正如我现在已删除的答案中的 cmets 所述,我真的很惊讶 prop.DeclaringType 在这里返回 Bar 而不是 Foo。我不认为这是声明一个新方法,而是覆盖现有方法。 C# 规范这样说:“虚拟方法声明引入一个新方法,而覆盖方法声明专门化现有继承的虚拟方法,提供该方法的新实现。 "我想我不能说它是在声明什么,因为它是一个方法声明。棘手的东西。
    • 我很惊讶没有MethodInfo.OverriddenMember 或者MethodInfo.OriginalDeclaringType 或类似的东西来让您找出哪个成员被覆盖。 (就像有ReflectedType 来找出你问的是哪种类型。)很多不同的东西可能有用...
    猜你喜欢
    • 2014-01-17
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多