C# 中具有方差的通用方法?
考虑以下类(继承树):
public class A {}
public class B: A {}
而这种方法:
public IList<A> MyMethod(){
IList<B> result = new List<B>();
//add some items to result
return result;
}
编译器不高兴。错误是无法转换表达式类型IList;返回类型 IList
。我该如何解决这个问题?换句话说,如何指定 MyMethod
将返回 T
的 IList
,其中 T
可以是任何继承自 A
或 A
本身的实例?
Consider following classes (inheritance tree):
public class A {}
public class B: A {}
And this method:
public IList<A> MyMethod(){
IList<B> result = new List<B>();
//add some items to result
return result;
}
The compiler is unhappy. Error is Cannot convert expression type IList<B> to return type IList<A>
. How do I solve this ? In another words how to specify that MyMethod
will return IList<T>
of T
where T
can be anything that inherits from A
or instances of A
itself ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您所要求的是不可能的,因为
IList
不支持方差 - 您不能在任何需要IList 的地方使用
。您必须解释更多您想要的细节才能找到解决方案。IList
;可能的解决方案是:
或者
What you're asking for is impossible because
IList<T>
does not support variance -- you cannot useIList<B>
anywhere that is expectingIList<A>
. You'll have to explain more details of what you want in order to come up with a solution.Possible solutions are:
Or
您无法将 IList 转换为到 IList,即使 B 继承自 A。否则,用户可能会尝试将不是 B 的 A 实例添加到列表中。
你能返回 IEnumerable 吗?而不是 IList? IEnumerable与 IList 不同,它是协变的。
You cannot convert an IList<B> to IList<A>, even if B inherits from A. Otherwise, the user might attempt to add an instance of A that is not B into the list.
Can you return IEnumerable<A> instead of IList<A>? IEnumerable<A> is covariant, unlike IList<A>.
您不必这样做,
您只需声明它返回
IList
即可。为什么?因为 - 假设B
继承自A
-B
的每一项都可以在所需类型为A
的地方传递。称之为继承多态性、里氏替换原理或方法方差,名称并不重要。重要的是以下内容有效(在 LinqPad 上测试):
遗传替代方案
事实上,您可以知道您将返回一个
IList
并请求一些派生类型 (TB
,TC
...) 来填充它。是的,下面的示例也适用(在 LinqPad 上测试):或者,如果您想保留特定的基类型(假设您想返回一个
IList
但它实际上包含以下类的项目)从A
派生,那么你可以这样做:你不必这样做,但是
如果你真的想说它返回
IList
其中T: A
然后说!是的,那个不能返回
T
类型的项目和A
类型的项目,因为它说它返回>IList
并且并非A
类型的每个项目也是T
类型的项目您的代码会发生什么情况
查看您的代码:
您是尝试返回
IList
当您说您要返回一个IList
时,我们假设这有效...那么您的方法的调用者会发生什么?让我们看看:DFTBA!
You don't have to
You can just declare that it returns
IList<A>
. Why? Becase - given thatB
inherits fromA
- every item ofB
can be passed where the requiered type isA
.Call it polymorphism by inheritance, Liskov substitution principle, or method variance, the name doesn't matter. What matters is that the following works (tested on LinqPad):
Genetic alternatives
In fact, you can tell that you are going to return a
IList<TA>
and request a few derived types (TB
,TC
...) to populate it with. That's right, the following example also works (tested on LinqPad):Or if you want to keep a particular base type (say you want to return an
IList<A>
but it actually contains items of classes that derive fromA
, then you can do this:You don't have to, but you can
OK, if you really want to say it returns
IList<T>
where T : A
. Then say that!Yes, that one cannot return a mix of item of type
T
and items of typeA
, because it says it returnsIList<T>
and not every item of typeA
is also an item of typeT
.What happens with your code
Look at your code:
You are trying to return an
IList<B>
when you said that you was going to return anIList<A>
. Let's suppose that that works... then what would happen to the caller of your method? Let's see:DFTBA!