将泛型集合转换为基类型

时间:2021-06-02 21:46:55

I've got an IList<DerivedClass> that I want to cast to ICollection<BaseClass> but when I attempt an explicit cast, I get null. Is it possible to do this without creating and populating a new collection?

我有一个IList 我想要转换为ICollection 但是当我尝试显式转换时,我得到null。是否可以在不创建和填充新集合的情况下执行此操作?

Edit: Since I only want to read from the collection, I switched to using a generic method:

编辑:由于我只想从集合中读取,我转而使用泛型方法:

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

Then I can pass it an IList<DerivedClass>. Is there a good way to cache this list so I can refresh it when I need to. My first inclination is to use:

然后我可以传递一个IList 。有没有一种很好的方法来缓存此列表,以便我可以在需要时刷新它。我的第一个倾向是使用:

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>);
}

Does anyone have a better way of doing this?

有没有人有更好的方法这样做?

6 个解决方案

#1


The short answer is "No." You would need to create a new collection with the new BaseClass type and populate it.

最简洁的答案是不。”您需要使用新的BaseClass类型创建一个新集合并填充它。

If you think about it, it makes sense. If you could simply "cast" your collection to BaseClass, you could then stick something that was of type "BaseClass" into it, thereby forcing a simple BaseClass object into a DerivedClass Collection. This would defeat the purpose creating a Collection with Type-Safety.

如果你考虑一下,这是有道理的。如果您可以简单地将您的集合“强制转换”为BaseClass,那么您可以将类型为“BaseClass”的东西粘贴到其中,从而将简单的BaseClass对象强制转换为DerivedClass集合。这将破坏创建具有类型安全性的集合的目的。

In the extreme case, if you had two derived classes, Foo and Bar, you could force Bar objects into a collection of Foo objects by type-casting the collection back to a collection of BaseClass.

在极端情况下,如果您有两个派生类Foo和Bar,则可以通过将集合类型转换回BaseClass集合来强制将Bar对象强制转换为Foo对象的集合。

#2


This is called co-variance and while not currently supported with generics in .net, it will be added in the 4.0 framework (along with the opposite which is contra-variance).

这被称为协方差,虽然目前在.net中不支持泛型,但它将被添加到4.0框架中(以及相反的反向差异)。

This excellent video from PDC 2008 is session on C# futures given by Anders Hejlsberg:

来自PDC 2008的精彩视频是由Anders Hejlsberg提供的关于C#期货的会议:

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

#3


I don't think it's possible, and indeed it shouldn't be:

我不认为这是可能的,事实上它不应该是:

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());
}

#4


Switching between generic containers of derived classes and base classes is not supported. (It does work with arrays) It is possible to write a type converter to reasonably cleanly perform the switch without manually copying elements between the lists.

不支持在派生类和基类的通用容器之间切换。 (它适用于数组)可以编写一个类型转换器,以合理地干净地执行切换,而无需在列表之间手动复制元素。

Check out this link for a description of the issue/limitation and a solution: http://www.25hoursaday.com/weblog/CommentView.aspx?guid=AF7AA888-A227-454C-8687-71FA77186064

查看此链接以获取问题/限制的说明和解决方案:http://www.25hoursaday.com/weblog/CommentView.aspx?guid = AF7AA888-A227-454C-8687-71FA77186064

Down at the bottom is a nice generic-enabled version.

在底部是一个很好的通用版本。

#5


If .NET 3.5 is an option, you can use the Cast<T> extension method in System.Core.dll to get a read-only IEnumerable<T> for the collection:

如果.NET 3.5是一个选项,您可以使用System.Core.dll中的Cast 扩展方法获取集合的只读IEnumerable :

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

#6


You can cast each element into new iterator:

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

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

#1


The short answer is "No." You would need to create a new collection with the new BaseClass type and populate it.

最简洁的答案是不。”您需要使用新的BaseClass类型创建一个新集合并填充它。

If you think about it, it makes sense. If you could simply "cast" your collection to BaseClass, you could then stick something that was of type "BaseClass" into it, thereby forcing a simple BaseClass object into a DerivedClass Collection. This would defeat the purpose creating a Collection with Type-Safety.

如果你考虑一下,这是有道理的。如果您可以简单地将您的集合“强制转换”为BaseClass,那么您可以将类型为“BaseClass”的东西粘贴到其中,从而将简单的BaseClass对象强制转换为DerivedClass集合。这将破坏创建具有类型安全性的集合的目的。

In the extreme case, if you had two derived classes, Foo and Bar, you could force Bar objects into a collection of Foo objects by type-casting the collection back to a collection of BaseClass.

在极端情况下,如果您有两个派生类Foo和Bar,则可以通过将集合类型转换回BaseClass集合来强制将Bar对象强制转换为Foo对象的集合。

#2


This is called co-variance and while not currently supported with generics in .net, it will be added in the 4.0 framework (along with the opposite which is contra-variance).

这被称为协方差,虽然目前在.net中不支持泛型,但它将被添加到4.0框架中(以及相反的反向差异)。

This excellent video from PDC 2008 is session on C# futures given by Anders Hejlsberg:

来自PDC 2008的精彩视频是由Anders Hejlsberg提供的关于C#期货的会议:

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

#3


I don't think it's possible, and indeed it shouldn't be:

我不认为这是可能的,事实上它不应该是:

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());
}

#4


Switching between generic containers of derived classes and base classes is not supported. (It does work with arrays) It is possible to write a type converter to reasonably cleanly perform the switch without manually copying elements between the lists.

不支持在派生类和基类的通用容器之间切换。 (它适用于数组)可以编写一个类型转换器,以合理地干净地执行切换,而无需在列表之间手动复制元素。

Check out this link for a description of the issue/limitation and a solution: http://www.25hoursaday.com/weblog/CommentView.aspx?guid=AF7AA888-A227-454C-8687-71FA77186064

查看此链接以获取问题/限制的说明和解决方案:http://www.25hoursaday.com/weblog/CommentView.aspx?guid = AF7AA888-A227-454C-8687-71FA77186064

Down at the bottom is a nice generic-enabled version.

在底部是一个很好的通用版本。

#5


If .NET 3.5 is an option, you can use the Cast<T> extension method in System.Core.dll to get a read-only IEnumerable<T> for the collection:

如果.NET 3.5是一个选项,您可以使用System.Core.dll中的Cast 扩展方法获取集合的只读IEnumerable :

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

#6


You can cast each element into new iterator:

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

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