为什么';t类型约束是方法签名的一部分

本文关键字:方法 一部分 约束 类型 为什么 | 更新日期: 2023-09-27 18:25:41

更新:从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>是最佳重载匹配,但随后类型约束失败,并引发编译时错误。用埃里克的话说:

这里的原理是重载解析(和方法类型推断)在参数列表和每个候选方法的形式参数列表之间找到尽可能好的匹配。也就是说,他们查看候选方法的签名。

类型约束不是签名的一部分,但为什么不能呢?在哪些情况下,将类型约束作为签名的一部分是个坏主意实施起来是困难还是不可能?我并不主张,如果出于任何原因,最好选择的过载是不可能调用的,那么就默默地回退到第二个最佳;我讨厌那样。我只是想了解为什么不能使用类型约束来影响最佳重载的选择。

我想象在C#编译器内部,仅用于过载解决目的(它不会永久重写方法),如下所示:

static void Foo<T>(T t) where T : Reptile { }

转换为:

static void Foo(Reptile  t) { }

为什么不能将类型约束"拉入"到形式参数列表中?这是如何以任何不好的方式更改签名的?我觉得这只会加强签名。那么CCD_ 3将永远不会被认为是过载候选者。

编辑2:难怪我的问题如此令人困惑。我没有正确阅读孙的博客,我引用了错误的例子。我编辑了我认为更合适的例子。我还把标题改得更具体一些。这个问题似乎并不像我最初想象的那么简单,也许我错过了一些重要的概念。我不太确定这是堆叠式的材料,这个问题/讨论最好转移到其他地方。

为什么';t类型约束是方法签名的一部分

C#编译器不必将类型约束视为方法签名的一部分,因为它们不是CLR方法签名的组成部分。如果重载解决方案对不同的语言起到不同的作用,那将是灾难性的(主要是由于运行时可能发生的动态绑定,并且不同语言之间不应该有不同,否则所有的地狱都会崩溃)。

为什么决定这些约束不作为CLR方法签名的一部分是另一个问题,我只能对此做出不明智的假设。我会让知情人士回答的。

如果T与多个约束匹配,则会产生无法自动解决的模糊性。例如,您有一个具有约束的泛型类

where T : IFirst

另一个具有约束

where T : ISecond

现在您希望T是一个同时实现IFirstISecond的类。

具体代码示例:

public interface IFirst
{
    void F();
}
public interface ISecond
{
    void S();
}
// Should the compiler pick this "overload"?
public class My<T> where T : IFirst
{
}
// Or this one?
public class My<T> where T : ISecond
{
}
public class Foo : IFirst, ISecond
{
    public void Bar()
    {
        My<Foo> myFoo = new My<Foo>();
    }
    public void F() { }
    public void S() { }
}