2013-03-22 79 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