Hier ist eine einfache Anwendung, die die Methode Signatur eines MethodCallExpression
druckt:MethodCallExpression.Method gibt immer die Wurzel Basisklasse Method
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());
}
}
ich das Programm auszudrucken erwarten:
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()
Aber es druckt stattdessen aus:
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()
Wenn Sie diebekommenEigenschaft für die vererbte MethodCallExpression
, gibt es immer A
s MethodInfo
(die Stammklasse) zurück.
Allerdings, in Visual Studio und ich "Go to Definition" von jedem der Foo()
Aufrufe, bin ich zu jeder der überschriebenen Methoden wie erwartet übernommen.
Warum verhält sich das MethodCallExpression.Method
so? Gibt es irgendetwas in der Spezifikation? Warum gibt es eine Diskrepanz zwischen VS und der Method
Eigenschaft? Ich habe mit .NET 4.0 und 4.5 getestet.
Gute Frage. Dieses Verhalten scheint intuitiv korrekt zu sein, wenn man an den generierten Code denkt - in allen 3 Fällen ist es ein Callvirt zu "A.Foo". –
Dieses Verhalten wurde im C# -Sprache-Design-Repository auf GitHub erwähnt: siehe https://github.com/dotnet/roslyn/issues/24347#issuecomment-359070141. – stakx