哦,当我试图做一些简单的事情时,我遇到了麻烦。
原来C# 4允许这种协变——有点像。首先,我必须将Thing变成一个接口,并指定“out”泛型参数:
public interface Thing<out T> {...}
但是如果我做了某些事情,C# 就不让我使用协变性。例如,如果我尝试从接口返回 T:
public interface Thing<out T>
{
public T GetT();
即使我成功地使用Thing得到了协方差,那我该怎么处理它呢?
Thing<object> thing=createThing()
编译器告诉我无法从使用中推断出类型。
假设我放弃整个 T 的概念,让工厂方法返回类型为 object 的 Thing:
public static Thing<object> createThing() {...}
好的,但现在我把它放在哪里?
IList<Thing<object>> list=new List<Thing<object>>()
Thing<object> thing=createThing()
list.Add(thing)
是的,我必须说这是一个类型为Object的Thing列表,因为C#没有通配符类型。
如果这是Java,我会简单地说:
public class Thing<T> {...}
public static <T> Thing<T> createThing() {...}
List<?> things=new ArrayList<Thing<?>>();
Thing<?> thing=createThing();
things.add(thing);
如果我想要通过指定 T 的特殊类型来获得额外的安全性,我会这样说:
public static <T extends MyBaseType> Thing<T> createThing() {...}
List<? extends MyBaseType> things=new ArrayList<Thing<? extends MyBaseType>>();
Thing<? extends MyBaseType> thing=createThing();
things.add(thing);
然后当我有更多信息时,我会弄清楚T是什么。
所有这些似乎都归结为C#中不完整的通用协变性以及缺乏C#通用通配符。(我仍然认为这不是一个擦除问题。)
那么我该怎么办?唯一简单的事情似乎是按照Reinderien的答案拆分出一个非通用基类。
(我想知道在这个非通用基类中是否可以有object getValue(),然后在子类中使用协变返回T getValue()?啊,我厌倦了这个问题——我将把它留到另一天。)
T
。 - Adam RobinsonThing<Int>
和Thing<String>
是完全不同的类型。是的,接口支持泛型协变和逆变,但是a)它仅适用于接口(您的代码暗示了一个类),并且b)您仍然必须有一个基础类型。您不能有一个“通配符”。 - Adam Robinson