【问题标题】:convert generic type to base class将泛型类型转换为基类
【发布时间】:2019-03-25 15:38:47
【问题描述】:
public class Base {...}

public class Complex: Base {...}

public class MyOtherClass<T> {...}

以及两种类型的列表

List<MyOtherClass<Complex>> listOfComplex
List<MyOtherClass<Base>> listOfBase

我想要一份清单

listOfComplex.Union(listOfBase)

但我无法将一种类型的泛型转换为另一种类型的泛型,即使 Complex 派生自 Base 有可能有一个基类的列表吗?

【问题讨论】:

    标签: c# generics


    【解决方案1】:

    虽然Complex 派生自Base,但MyOtherClass&lt;Complex&gt;MyOtherClass&lt;Base&gt; 之间没有这种关系。这就是您无法创建两个列表的Union 的原因。对于框架,两种泛型类型完全不同

    现在的解决方案实际上取决于您的班级究竟做了什么。在 Docs 中查看协变和逆变主题 - 这是两种特殊情况,如果类型仅为输入或输出,您将被允许在两种泛型类型之间创建转换。

    您还可以在执行“联合”操作之前添加自定义转换或手动将项目转换为“基本”类型。

    【讨论】:

      【解决方案2】:

      因为Covariance and Contravariance in Generics是这样工作的,特别是invariance,这意味着你只能使用最初指定的类型;所以一个不变的泛型类型参数既不是协变的也不是逆变的。

      您不能将List&lt;Base&gt; 的实例分配给List&lt;Complex&gt; 类型或相反方向的变量。同样适用于自定义泛型类。编译器不能使用隐式转换来转换类型。

      即使你添加了泛型类型约束。 A&lt;B&gt;A&lt;C&gt;是两种不同的类型,即使C继承自B(因为AC不是继承自AB

      【讨论】:

        【解决方案3】:

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

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

        然后您可以将MyOtherClassBase 明确指定为Union 的通用参数。现在,Union 将需要 IEnumerable&lt;MyOtherClassBase&gt; 类型的输入。 List&lt;MyOtherClass&lt;T&gt;&gt; 类型的列表与 IEnumerable&lt;MyOtherClassBase&gt; 的赋值兼容。

        var result = listOfComplex.Union<MyOtherClassBase>(listOfBase);
        

        注意声明中的out关键字

        public interface IEnumerable<out T> : System.Collections.IEnumerable
        

        它使接口协变。另请参阅 SO question <out T> vs <T> in Generics,尤其是 Reed Copsey 的 answer

        【讨论】:

          【解决方案4】:

          您应该在泛型中指定 T 是基于 Type 的类:

          public class MyOtherClass<T> where T : Base {...}
          

          只有在从 Base 派生并且 Union 应该可以工作时才会接受 T

          这里有一些关于泛型的文档,感谢@Marie:

          https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters

          【讨论】:

          • 您可能需要包含官方文档的链接。我假设 OP 不熟悉 generic type constraint
          • 另外,为了扩展这个答案@user3401335,没有通用约束(where T : Base)你可以做new List&lt;MyOtherClass&lt;Apple&gt;&gt;。显然ComplexApple 不会兼容。为了确保它不会炸毁,Union 将验证传入的List&lt;T&gt;s 的类型以确保它们兼容。
          • 即使使用类型约束也不起作用,因为约束不会在两者之间创建继承关系。
          猜你喜欢
          • 2017-09-22
          • 2010-10-07
          • 1970-01-01
          • 2019-09-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-02-19
          相关资源
          最近更新 更多