[英]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...
Seems like when using generics, the compiler won't cast a inner generic type (Base/Sub) in the generic type (OtherBase/OtherSub).似乎在使用 generics 时,编译器不会在泛型类型(OtherBase/OtherSub)中转换内部泛型类型(Base/Sub)。 Why does this happen?为什么会这样?
Update : Please also explain the difference between the above and the following (which works)更新:还请解释上面和下面的区别(有效)
void Call<T>() where T : Base { }
//...
Call<Sub>();
Forbidding this behaviour (known as “generic variance”) is necessary because otherwise the following code would compile:禁止这种行为(称为“通用方差”)是必要的,否则以下代码将编译:
List<string> strlist = new List<string>();
List<object> objlist = strlist;
objlist.Add(42);
We've added a number to a list of strings.我们在字符串列表中添加了一个数字。 Not good.不好。 (Incidentally, the code would compile for arrays instead of List
s because Java allowed this for some reason; however, this will raise a runtime exception.) (顺便说一句,代码将编译为arrays而不是List
s,因为 Java 出于某种原因允许这样做;但是,这将引发运行时异常。)
You can avoid this in your case though:不过,您可以在您的情况下避免这种情况:
static void Call<U, T>(T x) where U : Base where T : OtherBase<U> { }
And call it like this:并这样称呼它:
Call(new OtherSub<Sub());
C# 4.0 furthermore provides generic variance for interfaces . C# 4.0 还为接口提供了通用差异。 However, their use isn't often necessary.但是,它们的使用通常不是必需的。
Your issue is linked to a concept called variance/covariance.您的问题与称为方差/协方差的概念有关。 In fact, if A
inherits from B
, Class<A>
isn't a Class<B>
.事实上,如果A
继承自B
,则Class<A>
不是Class<B>
。
See this example:看这个例子:
Class<T>
exposes a public method foo(T param)
Class<T>
公开了一个公共方法foo(T param)
If Class<A>
was a Class<B>
, then a method having a reference to Class<B>
as a Class<A>
and calling foo(B param)
(with a B
instance) would be calling foo(A param)
.如果Class<A>
是Class<B>
,那么将Class<B>
引用为Class<A>
并调用foo(B param)
(带有B
实例)的方法将调用foo(A param)
. And B
isn't a A
.而且B
不是A
。
In fact, Class<A>
can inherit from Class<B>
only if T
is used as a return value only in Class<T>
.事实上, Class<A>
只有在T
仅在Class<T>
中用作返回值时才能从Class<B>
继承。
This is enforced in .NET 4 through the out keyword for generics interface.这是通过 generics 接口的 out 关键字在 .NET 4 中强制执行的。 Class<T>
could therefore implement IClass<out T>
. Class<T>
因此可以实现IClass<out T>
。
Konrad has a good advice on how to fix your code. Konrad 对如何修复代码有很好的建议。 If you wanted to use C# 4's variance, you could do it like this:如果你想使用 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>>()
would work then. Call<OtherSub<Sub>>()
会起作用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.