为什么类型约束不是方法签名的一部分?
所以我读了Eric Lippert的’Constraints不是签名的一部分’ ,现在我明白规范指定在重载解析后检查类型约束,但我仍然不清楚为什么必须如此。 以下是Eric的例子:
static void Foo(T t) where T : Reptile { } static void Foo(Animal animal) { } static void Main() { Foo(new Giraffe()); }
这不会编译因为: Foo(new Giraffe())
重载解析推断出Foo
是最佳的重载匹配,但是类型约束失败并抛出编译时错误。 用埃里克的话说:
这里的原则是重载决策(和方法类型推断)找到参数列表和每个候选方法的forms参数列表之间的最佳匹配。 也就是说,他们会查看候选方法的签名。
类型约束不是签名的一部分,但为什么不能呢? 在某些情况下,考虑类型约束是签名的一部分是个坏主意吗? 难道或难以实施? 我并不是在提倡如果最佳选择的超载是出于无论什么原因无法调用的话,那么就会默默地回归到第二好的; 我讨厌那个。 我只是想了解为什么不能使用类型约束来影响最佳过载的选择。
我在C#编译器内部想象, 仅用于重载解析(它不会永久重写方法) ,如下所示:
static void Foo(T t) where T : Reptile { }
变成了:
static void Foo(Reptile t) { }
为什么不能将类型约束“拉入”forms参数列表? 这怎么会以任何不好的方式改变签名? 我觉得它只会加强签名。 那么Foo
将永远不会被视为超载候选者。
编辑2:难怪我的问题太混乱了。 我没有正确阅读Eric的博客,我引用了错误的例子。 我在示例中编辑了我觉得更合适。 我也把标题更改为更具体。 这个问题似乎并不像我最初想象的那么简单,也许我错过了一些重要的概念。 我不太确定这是stackoverflow材料,将这个问题/讨论转移到其他地方可能是最好的。
C#编译器不必将类型约束视为方法签名的一部分,因为它们不是CLR的方法签名的一部分。 如果重载解析对于不同语言的工作方式不同(主要是由于动态绑定可能在运行时发生并且不应该从一种语言到另一种语言不同,或者所有地狱都会破裂),这将是灾难性的。
为什么决定这些约束不会成为CLR方法签名的一部分完全是另一个问题,我只能对此做出不明智的假设。 我会让知情人回答这个问题。
如果T
匹配多个约束,则会产生无法自动解析的歧义。 例如,您有一个带约束的generics类
where T : IFirst
和另一个有约束
where T : ISecond
您现在希望T成为实现IFirst
和ISecond
。
具体代码示例:
public interface IFirst { void F(); } public interface ISecond { void S(); } // Should the compiler pick this "overload"? public class My where T : IFirst { } // Or this one? public class My where T : ISecond { } public class Foo : IFirst, ISecond { public void Bar() { My myFoo = new My (); } public void F() { } public void S() { } }