[英]Casting generic container of type to container of inherited type?
If I have two classes: 如果我有两节课:
public class A { }
public class B : A { }
and I create a generic container and a function that takes it: 然后创建一个通用容器和一个使用它的函数:
public void Foo(List<A> lst) { ... }
I get an invalid conversion if I attempt casting a List<B>
to a List<A>
, and instead have to pass it like so: 如果我尝试将
List<B>
强制转换为List<A>
,则会得到无效的转换,而必须像这样传递它:
var derivedList = new List<B>();
Foo(new List<A>(derivedList));
Is there some way to pass a List<B>
to this function without the overhead of allocating a brand new list, or does C# not support converting from a generic container of a derived type to its base type? 是否有某种方法可以将
List<B>
传递给此函数而无需分配全新的列表,或者C#不支持从派生类型的泛型容器转换为其基本类型?
A List<B>
simply isn't a List<A>
- after all, you can add a plain A
to a List<A>
, but not to a List<B>
. List<B>
根本不是 List<A>
-毕竟,您可以将普通A
添加到List<A>
,但不能添加到List<B>
。
If you're using C# 4 and .NET 4 and your Foo method only really needs to iterate over the list, then change the method to: 如果您使用的是C#4和.NET 4, 并且 Foo方法只真正需要遍历列表,则将方法更改为:
public void Foo(IEnumerable<A> lst) { ... }
In .NET 4, IEnumerable<T>
is covariant in T
, which allows a conversion from IEnumerable<B>
(including a List<B>
) to IEnumerable<A>
. 在.NET 4中,
IEnumerable<T>
在T
是协变的,它允许从IEnumerable<B>
(包括List<B>
)转换为IEnumerable<A>
。 This is safe because values only ever flow "out" of IEnumerable<A>
. 这是安全的,因为值仅从
IEnumerable<A>
流出。
For a much more detailed look at this, you can watch the video of the session I gave at NDC 2010 as part of the torrent of NDC 2010 videos . 要对此进行更详细的了解,您可以观看我在NDC 2010上的会议视频,作为NDC 2010视频的洪流的一部分。
This is not possible. 这是不可能的。 C# doesn't support co / contra variance on concrete types such as
List<T>
. C#不支持诸如
List<T>
类的具体类型的co / contra差异。 It does support it on interfaces though so if you switch Foo
to the following signature you can avoid an allocation 它确实在接口上支持它,因此,如果将
Foo
切换到以下签名,则可以避免分配
public void Foo(IEnumerable<A> enumerable) { ...
If you wish to pass list-like things to routines which are going to read them but not write them, it would be possible to define a generic covariant IReadableList<out T> interface, so that an IReadableList<Cat> could be passed to a routine expecting an IReadableList<Animal>. 如果您希望将类似列表的内容传递给将要读取但不编写它们的例程,则可以定义通用协变IReadableList <out T>接口,以便将IReadableList <Cat>传递给例程需要IReadableList <Animal>。 Unfortunately, common existing IList<T> implementations don't implement any such thing, and so the only way to implement one would be to implement a wrapper class (which could accept an IList as a parameter), but it probably wouldn't be too hard.
不幸的是,现有的常见IList <T>实现并没有实现任何此类事情,因此,实现该问题的唯一方法是实现一个包装类(可以接受IList作为参数),但可能不会太难。 Such a class should also implement non-generic IList, also as read-only, to allow code to evaluate Count without having to know the type of the items in the list.
这样的类还应该实现非通用IList(也为只读),以使代码无需知道列表中项目的类型即可对Count进行评估。
Note that an object's implementation of IReadableList<T> should not be regarded as any promise of immutability. 注意,对象的IReadableList <T>的实现不应视为任何不变性的保证。 It would be perfectly reasonable to have a read-write list or wrapper class implement IReadableList<T>, since a read-write list is readable .
具有读写列表或包装器类实现IReadableList <T>是完全合理的,因为读写列表是可读的 。 It's not possible to use an IReadableList<T> to modify a list without casting it to something else, but there's no guarantee a list passed as IReadableList<T> can't be modified some other way, such as by casting it to something else, or by using a reference stored elsewhere.
无法使用IReadableList <T>修改列表而不将其强制转换为其他内容,但不能保证通过的列表无法通过其他方式修改IReadableList <T>,例如将其强制转换为其他方式,或使用其他位置存储的引用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.