为什么我得到这个编译错误试图调用一个基本构造函数/方法,接受一个动态参数

本文关键字:一个 方法 构造函数 参数 动态 错误 编译 调用 为什么 | 更新日期: 2023-09-27 18:14:34

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

构造函数调用需要动态分派,但不能这样做,因为它是构造函数初始化项的一部分。考虑强制转换动态参数。

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

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

如果我将参数强制转换为object,像这样:

public ClassB(dynamic test)
    : base((object)test)

所以,我有点困惑。为什么我要把这个讨厌的强制转换——为什么编译器不能理解我的意思?

为什么我得到这个编译错误试图调用一个基本构造函数/方法,接受一个动态参数

构造函数链必须在编译时确定-编译器必须选择一个重载以便它可以创建有效的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);
    }
}

编译器没有在这里发出对Foo的直接调用——它不能,因为在调用Foo(d)时它不知道它将解析到哪个过载。相反,它发出的代码做了一种"及时"的迷你编译,以在执行时使用d值的实际类型来解决过载。

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

你可能会说c#编译器应该能够告诉你实际上只有一个可见的构造函数可以调用,并且该构造函数总是可用…但是一旦你开始沿着这条路走下去,你最终会得到一种非常难以指定的语言。c#设计人员通常采用更简单的规则,这些规则有时并不像您希望的那样强大。