【问题标题】:Converting a List of Base type to a List of Inherited Type将基类型列表转换为继承类型列表
【发布时间】:2009-03-26 15:36:38
【问题描述】:

我可以肯定这个问题解决了之前问题中会提出的问题,但我找不到它。

C# 类中有一个方法将基类的通用列表作为参数。我需要传递一个继承类的列表,但不知道该怎么做。我在尝试中遇到错误。下面是示例代码来说明这一点:

public class A
{
   public static void MethodC(List<A>)
   {
       // Do Something here with the list
    }
}
public Class B : A
{
   // B inherits from A, A is the Base Class   
}

// Code utilizing the above method 
List<B> listOfB = new List<B>();
A.MethodC( (List<A>) listOfB );  // Error: this does not work
A.MethodC( listOfB.ToList<typeof(A)>() ); // Error: this does not work
A.MethodC( listOfB.ConvertAll<A>(typeof(A)) ); // Error: this does not work
// how can I accomplish this?  It should be possible I would think

注意:这是我的最终工作方法作为参考。我的问题得到了更好的解决方案,但从技术上讲,这不是问题的答案,因为我的问题措辞不当。

 public static DataTable 
    ObjectCollectionToDataTable<GLIST>
      (List<GLIST> ObjectCollection) where GLIST 
              : BaseBusinessObject
        {
            DataTable ret = null;

            if (ObjectCollection != null)
            {
                foreach ( var b in ObjectCollection)
                {

                    DataTable dt = b.ToDataTable();
                    if (ret == null)
                        ret = dt.Clone();
                    if (dt.Rows.Count > 0)
                        ret.Rows.Add(dt.Rows[0].ItemArray);
                }
            }

            return ret;
        }

【问题讨论】:

  • 这和我给你的答案一样......
  • 从技术上讲,这也是您最初提出的问题的答案! :)

标签: c# generic-list


【解决方案1】:

如果你有可用的 linq,你可以这样做

var ListOfA = ListOfB.Cast<A>().ToList();

【讨论】:

  • 我不认为我有 linq,但它仍然有效。非常感谢您的快速回复。
  • 可能的问题 - MethodC 是否需要修改列表,以便这些更改在 MethodC 之外可见?
  • 很高兴它成功了!我相信您拥有可用的 LINQ 扩展方法的唯一原因是在您的示例中使用了 ToList。
  • 现在,它不需要修改列表,它会遍历集合并在每个集合上调用抽象方法。
【解决方案2】:

你不能那样做。要理解为什么不允许这样做,想象一下如果 Add 在被转换为 List&lt;Derived&gt; 后被调用到 List&lt;Derived&gt; 会发生什么。

此外,暗示 C# 4.0 将有所不同的答案是错误的。永远不会修改列表以允许您执行此操作。只有 IEnumerable 会 - 因为它不允许将项目添加到集合中。

更新:它在您所寻求的解决方案中起作用的原因是因为您不再传递相同的列表。您正在创建一个全新的列表,它是原始列表的副本。这就是我询问修改列表的原因;如果MethodC 更改了列表中的项目数,这些更改将针对副本,而不是原始列表。

我认为最适合您的解决方案如下:

public abstract class A
{
    public void MethodC<TItem>(List<TItem> list) where TItem : A
    {
        foreach (var item in list)
            item.CanBeCalled();
    }

    public abstract void CanBeCalled();
}

public class B : A
{
    public override void CanBeCalled()
    {
        Console.WriteLine("Calling into B");
    }
}

class Program
{
    static void Main(string[] args)
    {
        List<B> listOfB = new List<B>();

        A a = new B();

        a.MethodC(listOfB);
    }
}

请注意,使用此解决方案,您可以将List&lt;B&gt; 直接传递给MethodC,而无需先对其进行奇怪的转换。所以没有不必要的复制。

之所以可行,是因为我们告诉MethodC 接受从A 派生的任何内容的列表,而不是坚持它必须是A 的列表。

【讨论】:

  • 我认为这不是真的,它工作正常。我的方法调用循环通过集合并作用于抽象(覆盖)方法和属性。我在之前的回复中使用了上面的代码,效果很好。该项目是 .NET 2.0,编译器为 CSC.exe (C#) 3.0。
  • 我猜你很难让它工作? :)
【解决方案3】:

您正在解决当前 C# 版本中缺乏协方差的问题。这是一种方法:

listOfB.Cast<A>();

【讨论】:

【解决方案4】:

这是一个答案,它将排除您列表中错误类型的任何对象。在我看来,这是一种更安全的方式:

List<A> ListOfA  = ListOfB.OfType<A>().ToList();

OfType 方法将排除错误派生类的项目,因为 Cast 将引发错误。

【讨论】:

    猜你喜欢
    • 2018-05-08
    • 1970-01-01
    • 2016-02-26
    • 1970-01-01
    • 2011-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多