在重构一些代码时,我遇到了这个奇怪的编译错误:
构造函数调用需要动态调度,但不能因为它是构造函数初始值设定项的一部分。考虑转换动态参数。
在尝试调用采用动态参数的基本方法/构造函数时,似乎会发生这种情况。例如:
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)
所以,我有点困惑。为什么我必须把这个讨厌的演员 - 为什么编译器不能弄明白我的意思?
答案 0 :(得分:42)
构造函数链必须在编译时确定 - 编译器必须选择一个重载,以便它可以创建有效的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)
中它不知道它会解析哪个重载。相反,它会发出一些代码,它执行一种“及时”的小型编译,以便在执行时使用{em>实际类型的d
来解决重载。
现在这对构造函数链不起作用,因为有效的IL必须包含对特定基类构造函数的调用。 (我不知道动态版本是否甚至不能在IL中表达,或者是否可以,但结果将无法验证。)
你可以说C#编译器应该能够告诉实际上只有一个可以可以被调用的可见构造函数,并且该构造函数总是可用。但是一旦你开始走这条路,你最终会得到一种非常复杂的语言。 C#设计师通常会采用更简单的规则,而这些规则有时并不像你希望的那样强大。