仿制药铸造

时间:2011-06-11 15:21:17

标签: c# generics

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...

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

更新: 还请解释上述和以下(有效)之间的区别

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

3 个答案:

答案 0 :(得分:8)

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

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

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

你可以在你的情况下避免这种情况:

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

并称之为:

Call(new OtherSub<Sub());

C#4.0还提供generic variance for interfaces。但是,它们的使用通常不是必需的。

答案 1 :(得分:3)

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

见这个例子:

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

如果Class<A>Class<B>,则引用Class<B>作为Class<A>并调用foo(B param)B的方法} instance)将调用foo(A param)。而B不是A

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

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

答案 2 :(得分:1)

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>>()会起作用。

相关问题