泛型和强制转换

10
class B : A {}
class Sub<T> where T:A
{
//...
}

我希望你能够在集合中存储Sub实例。
var c = new List<Sub<A>>();
c.Add(new Sub<B>()); //doesn't work

然而,为了使其真正起作用,我必须声明一个接口并存储该接口的实例。

interface IBase
{
    void DoStuff(A a);
}

var c = new List<IBase>();
c.Add(new Sub<B>()); //works

有没有更加优雅的方式来完成这个任务?


使用接口方法非常完美! - BonyT
2个回答

9

同一泛型类型使用不同的类型参数实例化后,它们是完全没有关系的。唯一的方法是将列表使用公共非泛型基类或接口,就像您在这里所做的那样。

您可以通过使用协变泛型接口来实现所需的近似效果:

class A { }
class B : A { }

interface ISub<out T> where T : A
{
    // Members go here
}

class Sub<T> : ISub<T> where T : A
{
    // Members go here.
}

以下是使用示例:

可以按照以下方式使用:

List<ISub<A>> list = new List<ISub<A>>();
list.Add(new Sub<B>());

你需要一个接口,因为只有接口可以具有协变或逆变的类型参数。


我本以为泛型约束 T:A 会让它工作 :( - jameszhao00
1
@jameszhao00:你需要协变性的原因是,如果没有它,你可能会在泛型类中有一个像void Foo(T value)这样的函数。如果将Sub<B>转换为Sub<A>,则允许您调用该函数并传递A的实例,而它只接受B的实例。通过指定类型参数是协变的,您不能在接口中使用带有泛型类型参数的参数(编译器不会编译它)。 - Sven

4

根据您的使用方式,但也许您可以为Sub使用协变接口:

interface ISub<out T> where T:A
{
}

那么通过引用转换,ISub<B> 可以隐式转换为 ISub<A>


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