所以我有一些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,BarA不能隐式转换为IBar。我想这里有一些我根本不见的东西。有人会对此有所了解吗?感谢。
答案 0 :(得分:4)
通用类型参数默认情况下既不是逆变量也不是协变量,但可以通过“in”和“out”关键字中的一个进行。
在IBar&lt; T,K&gt;的情况下,两个类型参数都用作输入和输出,因此您不能使它们成为逆变或协变。如果将它重构为两个接口,其中T仅用于输入而K仅用于输出,另一个T仅用于输出而K仅用于输入,那么您可以使每个类型参数协变或逆变关于它的用法。
答案 1 :(得分:2)
IBar
不是只读接口,因此您可能无法在C#中实现协调。您需要重构并提取只读接口,例如ReadOnlyBar,并在该接口上进行协调。 (免责声明 - 不是C#专家)
另一方面,Java的通配符可以将接口转换为只读和可变接口,因此IBar<? extends Animal>
是只读的,而IBar<? extends Tiger>
是它的子类型。这很酷,直到你的代码充满了许多通配符。