开发者

Casting generic container of type to container of inherited type?

If I have two classes:

public class A { }
public class B : A { }
开发者_如何学Python

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:

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?


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

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:

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>. This is safe because values only ever flow "out" of 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.


This is not possible. C# doesn't support co / contra variance on concrete types such as List<T>. It does support it on interfaces though so if you switch Foo to the following signature you can avoid an allocation

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

Note that an object's implementation of IReadableList<T> should not be regarded as any promise of immutability. It would be perfectly reasonable to have a read-write list or wrapper class implement IReadableList<T>, since a read-write list is readable. 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜