在C#中将引用转换为泛型类

时间:2015-07-27 08:53:43

标签: c# generics collections type-conversion

我在更复杂的上下文中尝试了泛型类转换,但首先发现它不可能。所以,为了示范目的,我写了这个样本,这是关于我能想到的最常见的问题,没有任何不必要的东西:

// The Typesafe repository
resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"

// Use the Play sbt plugin for Play projects
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.2.1")

所以一般来说:由于每个“Sub”都是“超级”,我认为每个“Sub of Generic”都是“Super of Generic”。所以我希望即使没有明确的类型转换,将using System; using System.Collections.Generic; namespace testapp { class Program { static void Main(string[] args) { // problem Generic<Sub> subvar = new Generic<Sub>(); Generic<Super> supervar; supervar = (Generic<Super>)subvar; // <--fails // reason for asking List<Generic<Super>> list = new List<Generic<Super>>(); list.Add(supervar); } } class Super { } class Sub:Super { } class Generic<T> where T : Super { } } 的引用分配给Generic<Sub>变量也没问题。

但.NET Framework告诉我这种转换是禁止的,为什么?

那么,我为什么要这样做呢?假设我想构建一个只接受“任何的泛型”的集合,我该如何绕过转换呢?

2 个答案:

答案 0 :(得分:3)

你偶然发现了通用差异的奇妙世界。泛型类总是类型不变的;换句话说,C<T1>无法转换为C<T2>,除非T1T2类型完全相同。

接口可以分别与inout声明逆变和协变。这允许分别“向上”和“向下”,但类不能。

有关方差的非常好的解释以及为List不变的原因,请参阅https://stackoverflow.com/a/2720046/7122

答案 1 :(得分:3)

如上所述:https://msdn.microsoft.com/en-us/library/dd469487.aspx您可以使用out Generic Modifier来实现目标。

为此,您必须添加一个如下所示的新接口:

interface IGeneric<out T> where T: Super{}

然后将您的通用类更改为:

class Generic<T> : IGeneric<T> where T : Super

然后你的主要是:

static void Main(string[] args)
{
    IGeneric<Sub> subvar = new Generic<Sub>();
    IGeneric<Super> supervar;
    supervar = subvar; // No cast required
    List<IGeneric<Super>> list = new List<IGeneric<Super>>();
    ist.Add(supervar);
}