将泛型类型转换为基类

3
public class Base {...}

public class Complex: Base {...}

public class MyOtherClass<T> {...}

并且有两种类型的列表
List<MyOtherClass<Complex>> listOfComplex
List<MyOtherClass<Base>> listOfBase

我想要一个列表

listOfComplex.Union(listOfBase)

但是我无法将一个类型的泛型转换为另一个类型的泛型,即使Complex是从Base继承而来的。是否可以拥有一个基类的列表?
4个回答

4
尽管 `Complex` 是从 `Base` 派生出来的,但是 `MyOtherClass<Complex>` 和 `MyOtherClass<Base>` 之间没有这样的关系。这就是为什么你不能创建两个列表的 Union 的原因。对于这个框架,这两个泛型类型是完全不同的
现在的解决方案取决于你的类到底要做什么。在此处查看协变和逆变的主题:Docs - 这是两种特殊情况,在这种情况下,如果类型是输入或输出,则允许你创建两个泛型类型之间的转换。
你也可以添加自定义转换或手动将项目强制转换为“基础”类型,然后执行“联合”操作。

2
因为这就是泛型中的协变和逆变的工作原理,具体来说是不变性,这意味着您只能使用最初指定的类型;因此,不变的泛型类型参数既不是协变的也不是逆变的。
您不能将List<Base>的实例分配给List<Complex>类型的变量或反过来。自定义泛型类也是如此。编译器无法使用隐式转换进行类型转换。
即使添加了泛型类型约束,A<B>A<C>也是两种不同的类型,它们之间没有转换,即使C继承自B(因为AC没有从AB继承)。

2

@MartinZikmund已经解释了为什么它不起作用。这种问题的解决方法要么是从一个非泛型基类派生泛型类,要么让它们实现一个共同的接口。

    public class MyOtherClassBase { }
    public class MyOtherClass<T> : MyOtherClassBase { }

然后,您可以明确将MyOtherClassBase指定为Union的通用参数。现在,Union将期望输入类型为IEnumerable<MyOtherClassBase>。类型为List<MyOtherClass<T>>的列表可以分配给IEnumerable<MyOtherClassBase>
var result = listOfComplex.Union<MyOtherClassBase>(listOfBase);

请注意声明中的 out 关键字。
public interface IEnumerable<out T> : System.Collections.IEnumerable

这使接口具有协变性。另请参见stackoverflow上的问题 泛型中的 <out T> 与 <T> 的区别,尤其是Reed Copsey的回答

0

1
您可能想在回答中包含官方文档的链接。我假设提问者不熟悉泛型类型约束 - Marie
1
此外,为了扩展@user3401335的答案,如果没有泛型约束(where T : Base),你可以使用new List<MyOtherClass<Apple>>。显然,ComplexApple不兼容。为了确保它不会崩溃,Union将验证传入的List<T>的类型以确保它们是兼容的。 - Marie
1
即使有类型约束,它也不起作用,因为约束没有在两者之间创建继承关系。 - Olivier Jacot-Descombes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接