【问题标题】:Collections with generic objects具有通用对象的集合
【发布时间】:2011-02-14 13:47:59
【问题描述】:

有一种方法将基础对象列表作为参数。

abstract class Base {}
class MyClass:Base {}
//...
void Method(List<Base> list) {}

当我调用该方法时,我想传递派生对象的列表。

var derivedList = new List<MyClass>();
Method(derivedList);

但我不能这样做,因为派生的集合与基础对象的集合不同。 处理这种情况的最佳做法是什么?现在我正在使用我的扩展 .ToBase() 来创建新集合,但我认为有更好的解决方案。

谢谢。

【问题讨论】:

    标签: c# oop collections


    【解决方案1】:

    使您的Method 通用:

    public void Method<T>(List<T> list) where T : Base
    {
        //Do your stuff
    }
    

    【讨论】:

      【解决方案2】:

      如果方法只是读取值,它可以声明为:

      void Method(IEnumerable<Base> list)
      

      这样,您的调用代码将在 C# 4 / .NET 4 中正常工作,无需任何更改。在 .NET 3.5 中,您可以使用

      Method(derivedList.Cast<Base>());
      

      如果您的方法是将值添加 到列表中,那么泛型协方差将不起作用并且不应该 起作用。毕竟,您不希望将派生自Base 的某个other 类的实例的引用添加到您的List&lt;MyClass&gt; 中,对吗?

      使Method 泛型(如 Klaus 所建议的那样)也可以在各种情况下工作,但也会使代码更加复杂。在不知道您的方法的作用的情况下,很难说这是否是一种好方法……尽管它绝对值得一试。

      【讨论】:

        【解决方案3】:

        Co-/contra-variance 是在 C#4.0 中实现的,这将允许您在需要 List&lt;Base&gt; 的方法中直接传递您的 List&lt;MyClass&gt; 而无需更多工作。

        在 C#3.5 中,您可以使用 Cast&lt;T&gt;() 扩展方法将一种类型的枚举转换为另一种类型,这将允许您将其转换为基本类型(每个条目的转换成本)。看来你已经用你的扩展方法.ToBase()

        【讨论】:

        • 方差只适用于接口,即使这样也只适用于满足某些条件的接口。 List 是一个类,IList 不是协变或逆变的。
        【解决方案4】:

        这是因为List&lt;MyClass&gt; 不是List&lt;Base&gt;

        你可以做的是:

        Method(derivedList.Cast<Base>().ToList());
        

        【讨论】:

          【解决方案5】:

          鉴于现有的方法签名,没有更好的解决方案。您尝试做的事情可以用原始数组来完成,但每个人都后悔了。问题是,如果您将 List&lt;Base&gt; 传递给某人,那么 应该 允许他们将其放置在 Base 或从它派生的任何内容中。但他们不能,因为它真的是List&lt;MyClass&gt;。如果允许的话,它会破坏很多东西。制作新系列是最好的方法。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-02-21
            • 1970-01-01
            相关资源
            最近更新 更多