为什么类型约束不是方法签名的一部分?

时间:2012-02-25 03:21:11

标签: c# generics overload-resolution type-constraints nested-generics

更新:从C#7.3开始,这应该不再是一个问题。从发行说明:

  

当方法组包含一些类型参数不满足其约束的泛型方法时,这些成员将从候选集中删除。

前C#7.3:

所以我读了Eric Lippert's 'Constraints are not part of the signature',现在我明白规范规定在超载分辨率之后检查类型约束,但是我仍然不清楚为什么必须如此。以下是埃里克的例子:

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) { }

为什么你不能&#34;拉入&#34;类型约束到形式参数列表?这怎么会以任何不好的方式改变签名?我觉得它只会加强签名。然后Foo<Reptile>永远不会被视为超载候选者。

编辑2:难怪我的问题太混乱了。我没有正确阅读Eric的博客,我引用了错误的例子。我在示例中编辑了我认为更合适的内容。我还将标题更改为更具体。这个问题看起来并不像我最初想象的那么简单,也许我错过了一些重要的概念。我不太确定这是否是stackoverflow材料,这个问题/讨论可能最好转移到其他地方。

2 个答案:

答案 0 :(得分:5)

C#编译器必须不考虑类型约束作为方法签名的一部分,因为它们不是CLR的方法签名的一部分。如果重载决策对于不同语言的工作方式不同(主要是由于动态绑定可能在运行时发生并且不应该从一种语言到另一种语言不同,或者所有地狱都会破裂),那将是灾难性的。

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

答案 1 :(得分:0)

如果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() { }
}