tags:

views:

108

answers:

4

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 class 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);
        }

    }
+1  A: 

In your exmaple, Super 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);
Allon Guralnek
I'm pretty sure that calling it through base is a requirement for it to become a base expression (which is my question). ;)Using object as an argument is the best workaround so far but still, I'm looking for an answer to why I'm not allowed to pass down a dynamic to a base method. What is the the real underlying problem here?
Ola Herrdahl
A: 

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.

Orsol
I don't think this will always work. For example, if you want to call the base class' method and the method is marked as virtual, your cast will cause the overridden method to be called instead.
Allon Guralnek
Yes, this won't work for virtual methods...
Ola Herrdahl
A: 

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
    }
}
Felix Ungman
It is obviously not supported, but why? That is the question here.
Ola Herrdahl
+4  A: 

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 Super 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 Super.MethodA() method. Which violates the base keyword contract.

Hans Passant
Ahh, finally someone who can answer the *why*. What do you mean by "Super class"? I only know the term as being synonymous with "base class".
Allon Guralnek
@Allon: it's in the OP's snippet.
Hans Passant
@Hans: Oh, pfff, silly me.
Allon Guralnek
Naming the subclass Super in the example was a bad move by me. I should have named it Subclass. I will change this in my original post so that it won't be so confusing in the future for others who stumbles over this question. @Hans, thanks for the answer!
Ola Herrdahl
@Ola: use Base + Derived, never leaves a guess.
Hans Passant
Even better, thanks!
Ola Herrdahl