2011-09-09 46 views
1

如果我有两类:将类型的泛型容器强制转换为继承类型的容器?

public class A { } 
public class B : A { } 

和我创建一个通用的容器,而这需要它的功能:

public void Foo(List<A> lst) { ... } 

我得到一个无效的转换,如果我试图铸造List<B>List<A>,而是必须通过它,像这样:

var derivedList = new List<B>(); 
Foo(new List<A>(derivedList)); 

是否有某种方式来传递一个List<B>这函数没有分配全新列表的开销,或者C#不支持从派生类型的泛型容器转换为其基类型?

+0

请参阅此处:http://stackoverflow.com/questions/1817300/convert-list-of-derived-class-objects-to-list-of-base-class-objects – SwDevMan81

+0

相关:http:// stackoverflow。 com/questions/686305 /转换成一个基类型的继承类型列表 – SwDevMan81

回答

4

一个List<B>根本不是一个List<A> - 毕竟,你可以添加一个普通AList<A>,而不是一个List<B>

如果您正在使用C#4和.NET 4 你的Foo方法只真正需要遍历列表,然后更改方法:

public void Foo(IEnumerable<A> lst) { ... } 

在.NET 4中,IEnumerable<T>covariant in T,其允许从IEnumerable<B>(包括List<B>)到IEnumerable<A>的转换。这是安全的,因为价值只会流出IEnumerable<A>

想要更详细地了解这一点,您可以观看我在NDC 2010上给出的作为torrent of NDC 2010 videos的一部分的会话视频。

1

这是不可能的。 C#不支持在具体类型(如List<T>)上进行共同/反对差异。它不支持它的接口虽然如此,如果你切换Foo下面签名就可以避免分配

public void Foo(IEnumerable<A> enumerable) { ... 
+0

IList <>没有工作,但IEnumerable <>做了。 – Michael

0

如果你想通过列表类似的东西例程这要读他们,但没有写他们,将有可能定义通用协变IReadableList接口,以便可以将IReadableList <Cat>传递给期望IReadableList的例程<Animal>。不幸的是,现有的IList实现不会实现任何这样的事情,因此实现它的唯一方法是实现一个包装类(它可以接受IList作为参数),但它可能不会太难。这样的类还应该实现非泛型IList,也是只读的,以允许代码评估计数,而不必知道列表中项目的类型。

请注意,IReadableList对象的实现不应被视为任何不可变性的承诺。由于读写列表是可读,因此读写列表或包装类实现IReadableList <T>将是完全合理的。无法使用IReadableList <T>来修改列表而不将其转换为其他内容,但不能保证列表已通过,因为IReadableList <T>无法以其他方式修改,例如将其转换为其他方式或者通过使用存储在别处的参考。