C# 中的强制转换问题
我有一个继承自 IList 的接口:
public interface IBase {}
public class Derived : IBase {}
public interface IMyList : IList<IBase> {}
我想将 IMyList
类型的变量转换为 IList
或 List
类型,以更容易或最有意义的为准。最好的方法是什么?
请注意,我使用的是 .NET 3.5
I have a interface that inherits from IList:
public interface IBase {}
public class Derived : IBase {}
public interface IMyList : IList<IBase> {}
I want to cast a variable of type IMyList
to type IList<Derived>
or List<Derived>
, whichever is easier or makes the most sense. What's the best way to do this?
Note that I'm using .NET 3.5
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
直接转换并不合适,因为可能会出现许多问题(
IMyList
可能包含Derived
以外的类型等),只要您不修改列表(在这种情况下,
IEnumerable
可以工作),您可以简单地:然后迭代结果。
编辑
根据下面OP的评论,还有两件事需要提及:
1)如果您需要一个
IList
,您可以简单地添加到上面并调用myList.Cast().ToList();
2) 如果这些确实是要求,那么您的代码没有任何意义。如果
IMyList
应该只包含Derived
对象,那么IMyList
应从IList
派生。请记住,虽然您知道只有一种类型实现 IBase 接口,但编译器并不那么具体。仅仅为了使用接口而到处使用接口对任何人都没有帮助!
A direct cast isn't going to be suitable since there are numerous problems that could occur (
IMyList
may contain types other thanDerived
, etc.)As long as you're not modifying the list (in which case,
IEnumerable<Derived>
would work) you could simply:And then iterate over the result.
Edit
Based on the OP's comment below, there are two other things to mention:
1) If you need an
IList<Derived>
, you could simply add to the above and callmyList.Cast<Derived>().ToList();
2) If those are truly the requirements, then your code doesn't make any sense. If
IMyList
should only ever containDerived
objects thenIMyList
should derive fromIList<Derived>
. Remember that while you know that there is only one type implementing theIBase
interface, the compiler doesn't so be specific.Using interfaces everywhere just for the sake of using interfaces doesn't help anybody!
然后你就陷入了你自己设计的痛苦世界。我的建议是首先找到其他方法来解决循环依赖问题。正如您所发现的,将所有内容都放入只有一种可能实现的接口中是解决该问题的一种痛苦方法。我不推荐它。
如果您做不到这一点,那么我会尝试修复有问题的函数,以便它采用
IList
、IEnumerable
或>IEnumerable<派生>
。优选IEnumerable解决方案之一;大多数采用列表的方法实际上只需要序列。如果您可以在此处解释为什么需要列表,这将有助于找到解决方法。如果您可以使其采用
IList
或IEnumerable
那么您就完成了;您手中已经有一些可以隐式转换为所需类型的东西。如果您可以使其采用。
IEnumerable
那么您可以说myListOfIBase.Cast()
(如果您确实知道所有这些都是 Derived)或myListOfIBase.OfType()
(如果您怀疑其中某些可能不是 Derived 类型并想跳过它们)并获取有效使用底层列表的 IEnumerable如果您无法更改有问题的函数,那么您可以创建自己的类来有效地使用底层列表:
然后将新的
MyProxyList
传递给该方法。Then you are in a world of pain of your own devising. My advice would be first to find some other way to solve your circular dependency problem. Making everything into interfaces that have only one possible implementation is a painful way to solve that problem, as you have discovered. I don't recommend it.
If you can't do that then I would try to fix the offending function so that it either takes an
IList<IBase>
, anIEnumerable<IBase>
or anIEnumerable<Derived>
. Preferably one of the IEnumerable solutions; most methods that take lists in fact only need sequences. If you could explain why you need a list here, that would be helpful in trying to find a workaround.If you can make it take an
IList<IBase>
orIEnumerable<IBase>
then you're done; you already have something in hand that is implicitly convertible to the desired type.If you can make it take an
IEnumerable<Derived>
then you can saymyListOfIBase.Cast<Derived>()
(if you really know that all of them are Derived) ormyListOfIBase.OfType<Derived>()
(if you suspect that some of them might not be of type Derived and want to skip them) and get anIEnumerable<Derived>
that efficiently uses the underlying list.If you cannot change the offending function then you can make your own class that efficiently uses the underlying list:
And then pass a new
MyProxyList
to the method..Net 3.5 没有通用协方差。演示一下:
不会编译成功。
解决方法
Justin Niessner 的回复中发布了 。这将起作用,但会导致整个列表的枚举(尽管此枚举被推迟)并且还返回一个可枚举值。要转换列表并最终得到 IList,您可以使用以下方法,
但是这是一种非常暴力的方法。这将产生一个新的单独的 IList,并将强制枚举整个列表。
.Net 3.5 does not have generic covariance. To demonstrate:
Will not compile successfully.
In Justin Niessner's response, the work around
was posted. This will work but will result in an enumeration of the entire list (although this enumeration is deferred) and also return an enumerable. To convert the list and end up with an IList you can use the following
This is a pretty brute-force approach however. This will result in a new and separate IList and will force an enumeration of the entire list.
由于
IList
允许T
类型的读取和写入操作,因此该接口既不是协变也不是逆变。因此,你想要的事情无法完成。想象一下下面的代码:Since
IList<T>
allows read and write operations of typeT
, the interface is neither co- nor contravariant. Thus, what you want cannot be done. Imagine the following code:如果您可以绝对确定所有实例都将是
Derived
类型,那么您可以使用Cast<>()
,并解决前面提到的性能问题。如果列表中可能存在除Derived
之外的内容,那么您将需要使用OfType()
来代替。非派生
项目将被排除而不是抛出。If you can be absolutely certain going forward that all instances will be of type
Derived
, then you can useCast<>()
, with the performance issues noted earlier. If there is a chance that something besidesDerived
will ever be in the list, then you'll want to useOfType<Derived>()
instead. Non-Derived
items would be excluded instead of throwing.在 .Net 3.5 中无法执行此操作,但在 .Net 4.0 中可以。
You can't do this in .Net 3.5, but you can in .Net 4.0.