Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't a base access expression be dynamically dispatched in C#?

Tags:

c#

dynamic

c#-4.0

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

    }
like image 629
Ola Herrdahl Avatar asked Aug 05 '10 11:08

Ola Herrdahl


2 Answers

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.

like image 58
Hans Passant Avatar answered Nov 17 '22 21:11

Hans Passant


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);
like image 29
Allon Guralnek Avatar answered Nov 17 '22 20:11

Allon Guralnek