C# E Visual Basic Geram Árvores De Expressões Diferentes
(Isto foi-me referido pelo Frans Bouma e explicado pelo Jon Skeet)
Imaginem este conjunto de classes:
public class A
{
public virtual string P
{
get { return "A"; }
}
}
public class B : A
{
}
public class C : B
{
public override string P
{
get { return "C"; }
}
}
E esta classe:
public static class Reporter
{
public static void Report<T>(T target, Expression<Func<T, string>> expression)
{
Console.WriteLine("Expression: {0}", expression);
Console.WriteLine("\tDeclaring Type: {0}", ((expression as LambdaExpression).Body as MemberExpression).Member.DeclaringType);
Console.WriteLine("\tInvocation Result: {0} for {1}", expression.Compile().Invoke(target), target.GetType());
Console.WriteLine();
}
}
A classe acima escreve na consola a expressão Lambda, o tipo que declara a propriedade e o valor da propridedade para target e o tipo de target.
Vejamos o que acontece quando é usado o seguinte código C#:
Reporter.Report(new C(), (A a) => a.P);
Reporter.Report(new C(), (B b) => b.P);
Reporter.Report(new C(), (C c) => c.P);
Reporter.Report(new B(), (A a) => a.P);
Reporter.Report(new B(), (B b) => b.P);
Reporter.Report(new A(), (A a) => a.P);
O resultado será:
Expression: a => a.P
Declaring Type: A
Invocation Result: C for C
Expression: b => b.P
Declaring Type: A
Invocation Result: C for C
Expression: c => c.P
Declaring Type: A
Invocation Result: C for C
Expression: a => a.P
Declaring Type: A
Invocation Result: A for B
Expression: b => b.P
Declaring Type: A
Invocation Result: A for B
Expression: a => a.P
Declaring Type: A
Invocation Result: A for A
Por outro lado, se for usado o seguinte código Visual Basic:
Reporter.Report(New C(), Function(a As A) a.P)
Reporter.Report(New C(), Function(b As B) b.P)
Reporter.Report(New C(), Function(c As C) c.P)
Reporter.Report(New B(), Function(a As A) a.P)
Reporter.Report(New B(), Function(b As B) b.P)
Reporter.Report(New A(), Function(a As A) a.P)
O resultado será:
Expression: a => a.P
Declaring Type: A
Invocation Result: C for C
Expression: b => b.P
Declaring Type: A
Invocation Result: C for C
Expression: c => c.P
Declaring Type: C
Invocation Result: C for C
Expression: a => a.P
Declaring Type: A
Invocation Result: A for B
Expression: b => b.P
Declaring Type: A
Invocation Result: A for B
Expression: a => a.P
Declaring Type: A
Invocation Result: A for A
Porquê as diferenças? Por causa das diferenças nas especificações e compiladores das diferentes inguagens:
- O compilador de C# gerará uma chamada virtual ao membro virtual na classe em que é declarado como virtual.
- O compilador de Visual Basic gerará uma chamada virtual ao membro sobreposto na classe em que é implementado.