将通用集合转换为基础类型

6

我有一个 IList<DerivedClass>,我想将其转换为ICollection<BaseClass>,但是当我尝试进行显式转换时,我得到了null。是否可以在不创建和填充新集合的情况下完成此操作?

编辑: 由于我只想从集合中读取,因此我切换到使用泛型方法:

public void PopulateList<BaseClass>(ICollection<T> collection)

那么我可以传递一个 IList<DerivedClass>。有没有一种好的方法来缓存这个列表,以便我需要时可以刷新它。我的第一个想法是使用:

Object cachedCollection;
Type cachedType;
public void PopulateList<BaseClass>(ICollection<T> collection) {
    cachedCollection = collection;
    cachedType = T;

    // other stuff...
}

private void Refresh() {
    PopulateList<cachedType>(cachedCollection as ICollection<cachedType>);
}

有没有更好的方法来做这件事?


一个代码示例会非常有帮助。没有它,很难给你任何有用的答案。 - Jim Mischel
7个回答

9
短而直接的回答是“不行”。您需要创建一个新集合,使用新的BaseClass类型并将其填充。
仔细考虑,这是有道理的。如果您可以仅仅“转换”您的集合为BaseClass,那么您就可以将一个类型为“BaseClass”的对象放入其中,从而将一个简单的BaseClass对象强制放入一个DerivedClass集合中。这将破坏创建具有类型安全性的集合的目的。
在极端情况下,如果您有两个派生类Foo和Bar,则可以通过将集合类型转换回一组BaseClass的集合来将Bar对象强制插入到Foo对象的集合中。

这很有道理。我只是从集合中读取,所以我没有考虑我想要做的事情的全部含义。 - dmo
var baseCollection = (ICollection)derivedList.CastToList<BaseType>(); 变量baseCollection = (ICollection)derivedList.CastToList<BaseType>(); - MarkDav.is

6

这被称为协变性,在当前的.net泛型中不支持,但它将在4.0框架中添加(以及相反的逆变性)。

这个来自PDC 2008的精彩视频是由Anders Hejlsberg提供的关于C#未来的讲座:

http://channel9.msdn.com/pdc2008/TL16/


谢谢提供信息,吉姆。我会看一下的。 - dmo

4

我认为这是不可能的,而且也不应该:

class BaseClass {}
class DerivedClass : BaseClass {}
class OtherClass : BaseClass {}

void test()
{
  List<DerivedClass> list = new List<DerivedClass>();
  slice(list); //you want to do this
}

void slice(IList<BaseClass> list)
{
  //yikes! adding OtherClass to List<DerivedClass>
  list.Add(new OtherClass());
}

1
在.NET 4.0中,通过使用“in”和“out”关键字来解决这种情况。 - sourcenouveau

2

没错,ConvertAll 是你的好帮手 :) - Martin Clarke

2

如果您可以使用.NET 3.5,您可以使用System.Core.dll中的Cast<T>扩展方法获取集合的只读IEnumerable<T>

using System.Linq;
...
private void Refresh() {
  PopulateList( cachedCollection.Cast<cachedType>( ) );
}

0

你可以将每个元素转换为新的迭代器:

var collectionOfBase = (collectionOfDerived as IEnumerable).Cast<BaseClass>();

0
ICollection<DerivedClass> cachedCollection;
Type cachedType;

public void PopulateList<BaseClass>(ICollection<T> collection) {
    cachedCollection = collection;
    cachedType = T;

    // other stuff...
}

private void Refresh() {
    PopulateList<cachedType>(cachedCollection.ToArray());
}

对我来说,调用cachedCollection.ToArray()是有效的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接