为什么不能在C#中动态调度基本访问表达式?

Ola*_*ahl 24 c# dynamic c#-4.0

我认为通过一个例子可以最好地理解这个问题,所以我们在这里:

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

    }
Run Code Online (Sandbox Code Playgroud)

编译器明确指出方法C是无效的,因为它使用基本访问来调用方法A.但为什么呢?

当用动态参数覆盖方法时,如何调用基本方法?

例如,如果我想做什么:

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

    }
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 20

是的,这在设计上是行不通的.base.MethodA()调用对虚拟方法进行非虚拟调用.编译器在非动态情况下为此发出IL几乎没有问题,因为它知道需要调用哪种特定方法.

动态调度并非如此.DLR的工作是确定需要调用哪种特定方法.它必须使用的是Derived类的MethodTable.该表并没有包含基类的治法方法的地址.它被覆盖覆盖了.它所能做的就是调用Derived.MethodA()方法.这违反了基本关键字合同.


All*_*nek 10

在您的示例中,Derived没有一个名为的方法MethodA,因此调用base.MethodA()与调用相同this.MethodA(),因此您可以直接调用该方法并完成它.但我假设你也有不同的this.MethodA(),你想能够打电话base.MethodA().在这种情况下,只需听取编译器的建议并将参数转换为object(记住这dynamic只是object编译器以特殊方式处理的):

base.MethodA((object)input);
Run Code Online (Sandbox Code Playgroud)