繁体   English   中英

Generics 铸件

[英]Generics Casting

interface Base { ... }
class Sub : Base { ... }

class OtherBase<T> where T : Base { ... }
class OtherSub<T> : OtherBase<T> where T : Base { ... }

//...in some class
void Call<T>() where T : OtherBase<Base> { }

//...
Call<OtherSub<Sub>>(); //compile fails...

似乎在使用 generics 时,编译器不会在泛型类型(OtherBase/OtherSub)中转换内部泛型类型(Base/Sub)。 为什么会这样?

更新:还请解释上面和下面的区别(有效)

void Call<T>() where T : Base { }
//...
Call<Sub>();

禁止这种行为(称为“通用方差”)是必要的,否则以下代码将编译:

List<string> strlist = new List<string>();
List<object> objlist = strlist;
objlist.Add(42);

我们在字符串列表中添加了一个数字。 不好。 (顺便说一句,代码将编译为arrays而不是List s,因为 Java 出于某种原因允许这样做;但是,这将引发运行时异常。)

不过,您可以在您的情况下避免这种情况:

static void Call<U, T>(T x) where U : Base where T : OtherBase<U> { }

并这样称呼它:

Call(new OtherSub<Sub());

C# 4.0 还为接口提供了通用差异 但是,它们的使用通常不是必需的。

您的问题与称为方差/协方差的概念有关。 事实上,如果A继承自B ,则Class<A>不是Class<B>

看这个例子:

Class<T>公开了一个公共方法foo(T param)

如果Class<A>Class<B> ,那么将Class<B>引用为Class<A>并调用foo(B param) (带有B实例)的方法将调用foo(A param) . 而且B不是A

事实上, Class<A>只有在T仅在Class<T>中用作返回值时才能从Class<B>继承。

这是通过 generics 接口的 out 关键字在 .NET 4 中强制执行的。 Class<T>因此可以实现IClass<out T>

Konrad 对如何修复代码有很好的建议。 如果你想使用 C# 4 的方差,你可以这样做:

interface IOtherBase<out T> where T : Base { }

class OtherBase<T> : IOtherBase<T> where T : Base { }
class OtherSub<T> : OtherBase<T> where T : Base { }

static void Call<T>() where T : IOtherBase<Base> { }

Call<OtherSub<Sub>>()会起作用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM