约束扩展方法产生了暧昧的呼叫

时间:2017-08-27 09:10:46

标签: c# generics

假设我们有两个不相关的接口

public interface IFirst
{

}

public interface ISecond
{

}

具有相同名称但受限于每个接口的扩展方法。

public static class IFirstExtensions
{
    public static void DoIt<TFirst>(this TFirst model)
        where TFirst : IFirst
    {

    }
}

public static class ISecondExtensions
{
    public static void DoIt<TSecond>(this TSecond model)
        where TSecond : ISecond
    {

    }
}

当我尝试使用IFirst实例时:

IFirst first = ...;
first.DoIt();

然后我收到错误:

  

“CS0121以下方法或属性之间的调用不明确:'IFirstExtensions.DoIt(TFirst)'和'ISecondExtensions.DoIt(TSecond)'”。

这很奇怪。看起来这两种方法在此范围内都可见。但是,如果我将它们命名为不同的,例如:

public static class IFirstExtensions
{
    public static void DoFirst<TFirst>(this TFirst model)
        where TFirst : IFirst
    {

    }
}

public static class ISecondExtensions
{
    public static void DoSecond<TSecond>(this TSecond model)
        where TSecond : ISecond
    {

    }
}

然后约束起作用,第二种方法不可见,引发编译错误:

IFirst first = ...;
first.DoSecond();

因此看起来这种约束条件在检测歧义和调用时会有所不同。但是在C#规范中,我发现只有一章与这个主题相关,严格地描述了约束是如何工作的。这是编译器中的错误还是我错过了什么?

1 个答案:

答案 0 :(得分:8)

通用约束不是方法签名的一部分。当涉及到重载分辨率时,两种方法都完全相同,因此会产生一个不明确的呼叫错误。

  

具体来说,方法的签名包括其名称,类型参数的数量,形式参数的数量,修饰符和类型( C#5.0规范,10.6方法

     

出于签名比较的目的,任何type-parameter-constraints-clause都会被忽略,方法的类型参数的名称也会被忽略,但泛型类型参数的数量是相关的( ECMA-334,25.6。 1通用方法签名

为了更清楚,当涉及到重载解析时,两种扩展方法都只是:

public static void DoFirst<T>(this T model)

另外,请注意该问题与扩展方法无关。请考虑以下示例,其中两个具有相同签名但具有不同约束的泛型方法在同一个类中声明:

class Foo
{
    void Bar<T>(Blah blah) where T: Frob { }
    void Bar<T>(Blah blah) where T: Blob { } //CS0111 error
}

您将收到编译时错误:

  

CS0111类型&#39; Foo&#39;已经定义了一个名为&#39; Bar&#39;具有相同的参数类型。