2012-12-05 38 views
6

我最近寫了這一點,並感到驚訝的是它編譯:泛型在C#中有多個泛型類型導致允許和不允許含糊

public class MyGeneric<U, V> { 
    MyGeneric(U u) { ... } 
    MyGeneric(V v) { ... } 
    public void Add(U u, V v) { ... } 
    public void Add(V v, U u) { ... } 
} 

如果我使用這個類,如下所示,我得到一個「不明確的構造函數引用」和一個「不明確的調用」,如果我打電話添加。

var myVar = new MyGeneric<int, int>(new MyIntComparer()); 

顯然,沒有歧義,當我用int和double作爲泛型類型,當然除了當我使用這兩個整數,這也將同時分配給雙。

var myVar = new MyGeneric<int, double>(new MyIntComparer()); 
myVar.Add(3, 5); 

那麼我認爲以下也是允許的,但令人驚訝的是我得到了一個錯誤。爲什麼下面不允許編譯?

public interface IMyInterface<T, S> { 
    void Add(T t, S s); 
} 

public class MyGeneric<U, V> : IMyInterface<U, V>, IMyInterface<V, U> { 
    public MyGeneric(U u) { } 
    public MyGeneric(V v) { } 
    void IMyInterface<U, V>.Add(U u, V v) { ... } 
    void IMyInterface<V, U>.Add(V v, U u) { ... } 
} 

無論我是否使用隱或顯式接口實現,編譯器指出

'MyGeneric < U,V >' 不能同時實現 'IMyInterface的< U,V >' 和「IMyInterface的< V,U >',因爲它們可能統一某些類型參數替換

爲什麼第一個分配結婚寫?

+2

雖然[這些](http://blogs.msdn.com/b/ericlippert/archive/2006/04/05/odious-ambiguous-overloads-part-one.aspx)[two](http:// blogs.msdn.com/b/ericlippert/archive/2006/04/06/odious-ambiguous-overloads-part-two.aspx)博客文章正在談論一種通用方法和非通用方法最終可能會出現的情況對某些類型參數使用相同的簽名,它們也可能適用於您的雙類型參數的情況。 (關於爲什麼允許這樣做的答案基本上是「我們允許它在C#2.0中,現在要更改它爲時已晚」)。 – Rawling

+0

感謝這些鏈接,它是編譯器的實現說明,我正在尋找 – AlexH

+0

@Rawling,感謝有趣的鏈接。 – Andreas

回答

4

1-爲什麼下面不允許編譯?響應

部分是在該職位:Why does the C# compiler complain that "types may unify" when they derive from different base classes?

的C#4規範規定的第13.4.2節:

由泛型類型聲明實現的接口必須保持 唯一所有可能的構造類型。如果沒有這條規則,那麼 就不可能確定調用某些 構造類型的正確方法。

2-爲什麼第一個被允許寫?

編譯器執行在編譯時所述類型檢查,C#4規範規定的節7.4.3.5:

雖然簽名所申報必須是唯一的,可能的是 取代類型參數導致相同的簽名。在 這樣的情況下,超負荷分辨率的決勝規則將在 以上挑選最具體的成員。下面的示例顯示重載 是根據這一規則有效和無效:

interface I1<T> {...} 
interface I2<T> {...} 
class G1<U> 
{ 
    int F1(U u);     // Overload resulotion for G<int>.F1 
    int F1(int i);     // will pick non-generic 
    void F2(I1<U> a);    // Valid overload 
    void F2(I2<U> a); 
} 
class G2<U,V> 
{ 
    void F3(U u, V v);   // Valid, but overload resolution for 
    void F3(V v, U u);   // G2<int,int>.F3 will fail 
    void F4(U u, I1<V> v);  // Valid, but overload resolution for 
    void F4(I1<V> v, U u);  // G2<I1<int>,int>.F4 will fail 
    void F5(U u1, I1<V> v2); // Valid overload 
    void F5(V v1, U u2); 
    void F6(ref U u);    // valid overload 
    void F6(out V v); 
} 
+0

感謝您的詳細解釋。確實,創建MyGeneric 基本上會實現相同的接口兩次,這就是爲什麼它會抱怨參數替換。 – Andreas

1

它的語言規範的一部分,作爲公認的答案在這裏解釋:

Why does the C# compiler complain that "types may unify" when they derive from different base classes?

科C#4規範的13.4.2規定:

如果有可能構造從C創建的類型將在類型參數被替換爲L之後,導致L中的兩個接口相同,那麼C的聲明是無效的。確定所有可能的構造類型時,不考慮約束聲明。

我猜你的兩個例子之間的不同之處在於第二個使用接口(檢查重複,每個語言規範),但第一次使用類型(不檢查重複,儘管你已經看到可能造成歧義) 。

+0

謝謝,沒錯,這基本上來自兩次相同的接口。 – Andreas

相關問題