2013-03-22 76 views
1

所以我有一些Java代碼,廣泛使用的泛型編譯得很好。我移植它交給C#如下: 泛型,協方差/反變量等

interface IFoo1 { } 
interface IFoo2 { } 

interface IBar<T, K> 
    where T : IFoo1 
    where K : IFoo2 { 
    List<T> GetFoo1s(); 
    void AddAFoo1(T foo1); 

    List<K> GetFoo2s(); 
    void AddAFoo2(K foo2); 
} 

interface IBlip<T> 
    where T : IBar<IFoo1, IFoo2> { 
    T DoBlip(string input); 
    void DoBlip2(T input); 
} 

interface IConverter<T, K> 
    where T : IBar<IFoo1, IFoo2> 
    where K : IBar<IFoo1, IFoo2> { 
    K Convert(T input); 
} 

class FooA1 : IFoo1 { } 
class FooB1 : IFoo1 { } 

class FooA2 : IFoo2 { } 
class FooB2 : IFoo2 { } 

class BarA : IBar<FooA1, FooA2> { 
    public List<FooA1> GetFoo1s() { return null; } 
    public void AddAFoo1(FooA1 foo1) { } 
    public List<FooA2> GetFoo2s() { return null; } 
    public void AddAFoo2(FooA2 foo2) { } 
} 

class BarB : IBar<FooB1, FooB2> { 
    public List<FooB1> GetFoo1s() { return null; } 
    public void AddAFoo1(FooB1 foo1) { } 
    public List<FooB2> GetFoo2s() { return null; } 
    public void AddAFoo2(FooB2 foo2) { } 
} 

class BlipA : IBlip<BarA> { 
    public BarA DoBlip(string input) { return null; } 
    public void DoBlip2(BarA input) { } 
} 

class BlipB : IBlip<BarB> { 
    public BarB DoBlip(string input) { return null; } 
    public void DoBlip2(BarB input) { } 
} 

class ConverterImplementation : IConverter<BarA, BarB> { 
    public BarB Convert(BarA input) { 
     return null; 
    } 
} 

當我編譯此,它抱怨說,例如,與ConverterImplementation,即巴不能被隱式轉換爲IBAR。我想這裏有一些我從根本上缺失的東西。有人可以解釋一下嗎?謝謝。

+4

搜索C#,老虎和長頸鹿。相信我這一個。 – 2013-03-22 21:04:58

+0

對於記錄(和鏈接頁面):http://stackoverflow.com/questions/4669858/simple-examples-of-co-and-contravariance和http://stackoverflow.com/questions/5881677/why-cant -i-cast-from-a-listmyclass-to-listobject – arcain 2013-03-22 21:22:55

+0

對不起,如果問題與其他人類似。這個例子似乎比我在那裏看到的其他一些例子更有意義,所以只是看看有沒有人有任何提示或技巧。我認爲最終我將不得不重新設計我的API。 – 2013-03-22 22:04:03

回答

4

通用類型的參數是默認既不逆變也不協變,但是可以由一個或通過「在」和「out」的關鍵字的其他。在這種情況下,兩個類型參數都用作輸入和輸出,所以你不能使它們變爲逆變或協變。如果將它重構爲兩個接口,其中一個T僅用於輸入,K僅用於輸出,另一個接口T僅用於輸出,K僅用於輸入,則可以使每個類型參數協變或逆變在其使用上。

+0

這就是我所害怕的。我想念Java類型擦除。 – 2013-03-22 22:02:16

2

IBar不是隻讀接口,因此你可能無法達到在C#convariance。您需要重構並提取只讀界面,例如ReadOnlyBar,並在該接口上進行convariance。 (免責聲明 - 而不是在C#專家)

在另一方面,Java的通配符可以打開的界面設置爲只讀和convariant接口,所以IBar<? extends Animal>是隻讀的convariant和IBar<? extends Tiger>是它的一個亞型。這很酷,所有,直到你的代碼散佈着大量的通配符。

+0

好Java類型的答案,謝謝。 – 2013-03-22 22:03:03