2017-08-27 110 views
3

让我们假设我们有两个不相关的接口约束扩展方法产生ambigious呼叫

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 The call is ambiguous between the following methods or properties: 'IFirstExtensions.DoIt(TFirst)' and '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(); 

所以看起来像这样的约束条件staisfying作品differenly含糊不清以及打电话时。但在C#规范中,我发现只有一篇与本主题相关的章节严格描述了约束是如何工作的。这是编译器中的错误还是我错过了一些东西?

回答

8

通用约束条件是不是方法签名的一部分。这两种方法在重载分辨率方面都完全相同,因此会产生一个模糊的调用错误。

Specifically, the signature of a method consists of its name, the number of type parameters and the number, modifiers, and types of its formal parameters (C# 5.0 Specification, 10.6 Methods)

For the purposes of signature comparisons any type-parameter-constraints-clauses are ignored, as are the names of the method’s type-parameters, but the number of generic type parameters is relevant (ECMA-334, 25.6.1 Generic method signatures)

说得更加清楚,当涉及到重载,既扩展方法是简单的:

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 Type 'Foo' already defines a member called 'Bar' with the same parameter types.

+0

Foo类从使用不同我讲过的无关课程。我会看到我的版本被关闭成签名,如:Bar(Frob blah),Bar(Blob blah)。这就是为什么而不是CS0111编译没有问题。如果你看一下MethodInfo-> Signature-> Arguments [0],你会看到在ImplementedInterfaces属性中具有不同值的绝对不同的类型。所以在运行时签名是不同的,它包含约束。 – Stan

+0

但你说得对。我错过了规范中的一点,通用约束官方忽略签名。这很荒谬。如果我将扩展IFirst/ISecond Inrerfaces - 这没关系。如果我将这些合同作为约束 - 事实并非如此。 – Stan

+0

@stan不,签名是相同的,错误是不同的,因为方法是在不同的类中定义的。当解决呼叫时,两种方法都在候选集合中,并且这是当识别签名发出庄稼并且呼叫被标记为不明确的时刻。之前没有给出该错误,因为当将其作为常规静态方法调用时,您总是可以明确定义实现扩展方法的静态类。对于实现两个具有相同方法签名和两个不同约束的接口的类,情况也是如此。 – InBetween