Ecco una semplice applicazione che stampa la firma del metodo di un MethodCallExpression
:MethodCallExpression.Method restituisce sempre MethodInfo della classe base di radice
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());
}
}
mi aspetterei il programma per stampare:
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()
Ma stampa invece:
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()
Quando si riceve il Method
proprietà per l'ereditato MethodCallExpression
, restituisce sempre A
s MethodInfo
(la classe radice).
Tuttavia, in Visual Studio e I "Vai a definizione" di ognuna delle chiamate Foo()
, sono portato a ciascuno dei metodi sottoposti a override come previsto.
Perché il MethodCallExpression.Method
si comporta in questo modo? C'è qualcosa nelle specifiche su questo? Perché c'è una discrepanza tra VS e la proprietà Method
? Ho provato con .NET 4.0 e 4.5.
Buona domanda. Questo comportamento sembra intuitivamente corretto se si pensa al codice che viene generato - in tutti e 3 i casi si tratta di un callvirt a 'A.Foo'. –
Questo comportamento è stato menzionato nel repository C# Language Design su GitHub: vedere https://github.com/dotnet/roslyn/issues/24347#issuecomment-359070141. – stakx