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

问题描述 投票:0回答:1

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

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

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

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)

所以,我有点困惑。为什么我必须放入这个令人讨厌的转换 - 为什么编译器不能弄清楚我的意思?

c# .net dynamic c#-4.0
1个回答
56
投票

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

编辑:在“普通”C# 代码中(基本上在 C# 4 之前),all 重载决策在编译时执行。但是,当成员调用涉及动态值时,该值将在执行时解析。例如考虑这个:

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 值的
actual
类型的重载。

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

您可能会争辩说,C# 编译器应该能够知道实际上只有一个可见的构造函数可以被调用,并且该构造函数将永远可用......但是一旦您开始沿着这条路走下去,您最终会使用一种“非常”难以指定的语言。 C# 设计者通常采取的立场是使用更简单的规则,但这些规则有时并不像您希望的那么强大。

© www.soinside.com 2019 - 2024. All rights reserved.