我在更复杂的上下文中尝试了泛型类转换,但首先发现它不可能。所以,为了示范目的,我写了这个样本,这是关于我能想到的最常见的问题,没有任何不必要的东西:
// 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告诉我这种转换是禁止的,为什么?
那么,我为什么要这样做呢?假设我想构建一个只接受“任何的泛型”的集合,我该如何绕过转换呢?
答案 0 :(得分:3)
你偶然发现了通用差异的奇妙世界。泛型类总是类型不变的;换句话说,C<T1>
无法转换为C<T2>
,除非T1
和T2
类型完全相同。
接口可以分别与in
和out
声明逆变和协变。这允许分别“向上”和“向下”,但类不能。
有关方差的非常好的解释以及为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);
}