更新: 截至C# 7.3版本,这个问题不再存在。从发行说明中可以看到:
当一个方法组包含一些泛型方法,其类型参数不满足其约束条件时,这些成员将被从候选集中移除。
C# 7.3之前:
我阅读了Eric Lippert的“约束不是签名的一部分”,现在我明白规范指定类型约束在重载解析之后进行检查,但我仍然不清楚为什么必须这样做。以下是Eric的例子:
static void Foo<T>(T t) where T : Reptile { }
static void Foo(Animal animal) { }
static void Main()
{
Foo(new Giraffe());
}
这个代码无法编译,因为对于
Foo(new Giraffe())
的重载解析推断出Foo<Giraffe>
是最佳匹配,但是类型约束失败并抛出编译时错误。用Eric的话来说:
类型约束不是签名的一部分,但为什么不能成为签名的一部分?有哪些场景不考虑类型约束会是一个坏主意?它只是难以实现还是不可能实现?我不是在主张如果选择的最佳重载由于某些原因无法调用,则悄悄地回退到第二个最佳重载;我会讨厌那样做。我只是想理解为什么类型约束不能用于影响选择最佳重载。原则上,重载解析(和方法类型推断)在参数列表和每个候选方法的形式参数列表之间寻找最佳匹配。也就是说,它们查看候选方法的签名。
我想象在C#编译器内部,仅用于重载解析目的(它不会永久重写方法),以下内容:
static void Foo<T>(T t) where T : Reptile { }
被转换为:
static void Foo(Reptile t) { }
为什么不能将类型约束“拉入”正式参数列表中?这会以何种不良方式改变签名呢?我觉得这只会增强签名。然后
Foo<Reptile>
就永远不会被视为重载候选项。
编辑2:难怪我的问题如此混乱。我没有正确阅读Eric的博客,并引用了错误的示例。我编辑了我认为更合适的示例。我还更改了标题以使其更具体。这个问题似乎不像我最初想象的那样简单,也许我错过了一些重要的概念。我不太确定这是否适合stackoverflow材料,最好将这个问题/讨论移动到其他地方。