I think this question is best understood by an example so here we go:
public class Base {
// this method works fine
public void MethodA(dynamic input) {
// handle input
}
}
public class Derived: Base { // Derived was named Super in my original post
// This is also fine
public void MethodB(dynamic input) {
MethodA(input);
}
// This method does not compile and the compiler says:
// The call to method 'MethodA' needs to be dynamically dispatched,
// but cannot be because it is part of a base access expression.
// Consider casting the dynamic arguments or eliminating the base access.
public void MethodC(dynamic input) {
base.MethodA(input);
}
}
The compiler clearly states that method C is invalid due to the fact that it is using base access to call method A. But why is that?
And how does one call the base method when overriding a method with dynamic parameters?
E.g. what if I wanted to do:
public class Base {
// this method works fine
public virtual void MethodA(dynamic input) {
Console.WriteLine(input.say);
}
}
public clas开发者_运维技巧s Derived: Base { // Derived was named Super in my original post
// this does not compile
public override void MethodA(dynamic input) {
//apply some filter on input
base.MethodA(input);
}
}
Yes, this cannot work by design. The base.MethodA() call makes a non-virtual call to a virtual method. The compiler has little trouble emitting the IL for this in the non-dynamic case since it knows what specific method needs to be called.
That's not the case for dynamic dispatch. It is the job of the DLR to figure out which specific method needs to be called. What it has to work with is the MethodTable of the Derived class. That table does not contain the address of the base class' MethodA method. It was overwritten by the override. All it can possibly do is call the Derived.MethodA() method. Which violates the base keyword contract.
In your example, Derived
doesn't have a method named MethodA
, so calling base.MethodA()
is the same as calling this.MethodA()
, so you can just call the method directly and be done with it. But I am assuming you also have a different this.MethodA()
and you want to be able to call base.MethodA()
. In this case, just listen to the compiler's advice and cast the argument to object
(remember that dynamic
is really just object
that the compiler treats in a special way):
base.MethodA((object)input);
The problem is not the dynamic argument but that the call uses the DLR to do the dispatching (which the following example illustrates). Perhaps that kind of call isn't supported by the DLR.
public class Base
{
public virtual void Method(int input)
{
}
}
public class Super : Base
{
public override void Method(int input)
{
dynamic x = input;
base.Method(x); // invalid
}
}
You can use this:
((Base)this).MethodA(input);
Specification said:
At binding-time, base-access expressions of the form base.I and base[E] are evaluated exactly as if they were written ((B)this).I and ((B)this)[E], where B is the base class of the class or struct in which the construct occurs
So, why your example gives error and this construction compiles well it is good question.
精彩评论