c# – MethodCallExpression.Method总是返回根基类的MethodInfo

这是一个打印MethodCallExpression的方法签名的简单应用程序:

using System;
using System.Linq;
using System.Linq.Expressions;

class A
{
    public virtual void Foo() { }
}

class B : A
{
    public override void Foo() { }
}

class C : B
{
    public override void Foo() { }
}

class Program
{
    static void Main(string[] args)
    {
        PrintMethod<A>(a => a.Foo());
        PrintMethod<B>(b => b.Foo());
        PrintMethod<C>(c => c.Foo());

        Console.Read();
    }

    static void PrintMethod<T>(Expression<Action<T>> expression)
    {
        var body = (MethodCallExpression)expression.Body;

        var method1 = body.Method;
        var method2 = typeof(T).GetMethod(body.Method.Name, body.Method.GetParameters().Select(p => p.ParameterType).ToArray());

        Console.WriteLine("body.Method         -> " + method1.DeclaringType.ToString() + " - " + method1.ToString());
        Console.WriteLine("typeof(T).GetMethod -> " + method2.DeclaringType.ToString() + " - " + method2.ToString());
    }
}

我希望该程序可以打印出来:

body.Method         -> A - Void Foo()
typeof(T).GetMethod -> A - Void Foo()
body.Method         -> B - Void Foo() *
typeof(T).GetMethod -> B - Void Foo()
body.Method         -> C - Void Foo() *
typeof(T).GetMethod -> C - Void Foo()

但它打印出来:

body.Method         -> A - Void Foo()
typeof(T).GetMethod -> A - Void Foo()
body.Method         -> A - Void Foo() *
typeof(T).GetMethod -> B - Void Foo()
body.Method         -> A - Void Foo() *
typeof(T).GetMethod -> C - Void Foo()

获取继承的MethodCallExpression的Method属性时,它始终返回As MethodInfo(根类).

但是,在每个Foo()调用的Visual Studio和I“Go To Definition”中,我按预期使用了每个重写的方法.

为什么MethodCallExpression.Method会以这种方式运行?这个规格中有什么内容吗?为什么VS和Method属性之间存在差异?我已经使用.NET 4.0和4.5进行了测试.

最佳答案
假设你有一个库:

public class A
{
    public virtual void Foo() { }
}

public class B : A
{
    public override void Foo() { }
}

public class C : B
{
    public override void Foo() { }
}

你有一个消费者

new C().Foo();

现在您更新库,以便C不再覆盖Foo:

public class C : B
{
}

消费者是否需要重新编译?

如果消费者虚拟地调用C.Foo,则是,并且消费者必须专门写((A)新的C()).Foo()以避免该问题.如果消费者虚拟地呼叫A.Foo,那么没有.由于这是唯一的区别,因为在运行时将调用完全相同的函数,因此消费者指定它调用C.Foo是没有意义的.

表达式树记录常规函数调用将记录的相同方法信息. C#规范几乎没有什么可说的,它留下了实现定义(但Microsoft的实现似乎没有定义(文档)它):

Conversion of an anonymous function to an expression tree type produces an expression tree (§4.6). More precisely, evaluation of the anonymous function conversion leads to the construction of an object structure that represents the structure of the anonymous function itself. The precise structure of the expression tree, as well as the exact process for creating it, are implementation defined.

转载注明原文:c# – MethodCallExpression.Method总是返回根基类的MethodInfo - 代码日志