【问题标题】:Casting a generic collection to base type将泛型集合转换为基本类型
【发布时间】:2010-10-07 01:26:12
【问题描述】:

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

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

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

然后我可以传递一个IList&lt;DerivedClass&gt;。是否有缓存此列表的好方法,以便我可以在需要时刷新它。我的第一个倾向是使用:

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

有人有更好的方法吗?

【问题讨论】:

  • 一个代码示例会很有帮助。没有它,很难给你任何有用的答案。

标签: .net generics collections


【解决方案1】:
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() 对我有用。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

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

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

        【讨论】:

        • 感谢您的信息,吉姆。我去看看。
        【解决方案5】:

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

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

        底部是一个不错的泛型版本。

        【讨论】:

        • 是的,ConvertAll 是你的朋友 :)
        【解决方案6】:

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

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

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

        【讨论】:

        • 这是有道理的。我只是从集合中阅读,所以我没有考虑我想做的事情的全部含义。
        • var baseCollection = (ICollection)derivedList.CastToList();
        【解决方案7】:

        我认为这不可能,实际上也不应该:

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

        【讨论】:

        • 在 .NET 4.0 中,这种情况通过使用“in”和“out”关键字来解决。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-22
        • 2020-08-26
        • 2016-11-15
        • 1970-01-01
        • 2019-09-16
        相关资源
        最近更新 更多