为什么在尝试调用采用动态参数的基础构造函数/方法时会出现此编译错误?

Dan*_*eny 46 .net c# compiler-construction dynamic c#-4.0

在重构一些代码时,我遇到了这个奇怪的编译错误:

构造函数调用需要动态调度,但不能因为它是构造函数初始值设定项的一部分.考虑转换动态参数.

当尝试调用采用动态参数的基本方法/构造函数时,似乎会发生这种情况.例如:

class ClassA
{
    public ClassA(dynamic test)
    {
        Console.WriteLine("ClassA");
    }
}

class ClassB : ClassA
{
    public ClassB(dynamic test)
        : base(test)
    {
        Console.WriteLine("ClassB");
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我将参数转换为object,它会起作用,如下所示:

public ClassB(dynamic test)
    : base((object)test)
Run Code Online (Sandbox Code Playgroud)

所以,我有点困惑.为什么我必须把这个令人讨厌的演员 - 为什么编译器不能弄明白我的意思?

Jon*_*eet 44

构造函数链必须在编译时确定 - 编译器必须选择一个重载,以便它可以创建有效的IL.通常,重载决策(例如,对于方法调用)可以推迟到执行时间,这对于链式构造函数调用不起作用.

编辑:在"普通"C#代码中(基本上在C#4之前),所有重载解析都在编译时执行.但是,当成员调用涉及动态值时,会在执行时解析.例如,考虑一下:

using System;

class Program
{
    static void Foo(int x)
    {
        Console.WriteLine("int!");
    }

    static void Foo(string x)
    {
        Console.WriteLine("string!");
    }

    static void Main(string[] args)  
    {
        dynamic d = 10;
        Foo(d);
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器不会向Foo此发出直接调用- 它不能,因为在调用中Foo(d)它不知道它将解析哪个重载.相反,它会发出代码,它执行一种"及时"的小型编译,以解决执行时实际值类型的重载问题d.

现在这对构造函数链不起作用,因为有效的IL必须包含对特定基类构造函数的调用.(我不知道动态版本是否甚至不能 IL 表示,或者它是否可以,但结果是无法验证的.)

您可以争辩说C#编译器应该能够告诉实际上只有一个可以被调用的可见构造函数,并且该构造函数将始终可用...但是一旦您开始这条道路,您最终会得到一种语言,即指定非常复杂.C#设计师通常会采用更简单的规则,而这些规则有时并不像你想要的那么强大.

  • 太好了,谢谢你的信息!我忘了动态的重载分辨率是在运行时(尽管在同一个项目中利用了它!).base*method*调用也会出现此错误,因此这似乎与基础相关而不是与构造函数相关.关于*为什么*的任何想法都不能在运行时完成? (2认同)