C# 将基类型的列表转换为继承类型的列表

C# 将基类型的列表转换为继承类型的列表,c#,generic-list,C#,Generic List,我可以肯定,这个问题涉及到了在前面的问题中可能会提出的一些问题,但我找不到它 C#类中有一个方法,它将基类的泛型列表作为参数。我需要传递一个继承类的列表,但我不知道该怎么做。我在尝试中出错了。下面是示例代码来说明这一点: public class A { public static void MethodC(List<A>) { // Do Something here with the list } } public Class B : A {

我可以肯定,这个问题涉及到了在前面的问题中可能会提出的一些问题,但我找不到它

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
公共A类
{
公共静态无效方法C(列表)
{
//在这里用列表做些什么
}
}
B级:A级
{
//B继承自A,A是基类
}
//使用上述方法的代码
List listOfB=新列表();
A.MethodC((列表)listOfB);//错误:这不起作用
A.MethodC(listOfB.ToList());//错误:这不起作用
A.MethodC(listOfB.ConvertAll(typeof(A));//错误:这不起作用
//我怎样才能做到这一点?我认为这应该是可能的
注:以下是我的最终工作方法,仅供参考。我找到了一个更好的解决问题的办法,但从技术上讲,这并不是问题的答案,因为我的问题措辞不当

 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;
        }
公共静态数据表
ObjectCollectionToDataTable
(列出ObjectCollection)其中
:BaseBusinessObject
{
DataTable ret=null;
if(ObjectCollection!=null)
{
foreach(ObjectCollection中的变量b)
{
DataTable dt=b.ToDataTable();
if(ret==null)
ret=dt.Clone();
如果(dt.Rows.Count>0)
ret.Rows.Add(dt.Rows[0].ItemArray);
}
}
返回ret;
}

如果您有linq可用,您可以

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

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

listOfB.Cast<A>();
listOfB.Cast();

您不能这样做。要理解为什么不允许这样做,请想象一下,如果在将
列表转换为
列表
后,对
列表
调用了
添加
,会发生什么情况

此外,暗示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);
    }
}
公共抽象类A
{
公共无效方法c(列表),其中TItem:A
{
foreach(列表中的变量项)
item.CanBeCalled();
}
公共摘要无效可以称为();
}
B级:A级
{
公共覆盖无效可以调用()
{
控制台写入线(“呼叫B”);
}
}
班级计划
{
静态void Main(字符串[]参数)
{
List listOfB=新列表();
A=新的B();
a、 方法c(列表b);
}
}
请注意,使用此解决方案,您可以将
列表
直接传递给
MethodC
,而无需首先对其进行奇怪的转换。因此,没有不必要的复制


之所以这样做,是因为我们告诉
MethodC
接受从
a
派生的任何对象的列表,而不是坚持它必须是
a

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

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

OfType方法将排除错误派生类的项,因为强制转换将抛出错误。

我认为我没有linq,但它仍然有效。非常感谢您的快速回复。可能的问题-MethodC是否需要修改列表,以便在MethodC之外可以看到这些更改?很高兴它成功了!我认为您可以使用LINQ扩展方法的唯一原因是您的示例中使用了ToList。现在,它不需要修改列表,它将遍历集合并对每个集合调用抽象方法。您可以跳过“.Cast”:var ListOfA=ListOfB.ToList();这只提供一个IEnumerable,而不是List。这是因为((List)listOfB.Cast())在我显式将其转换为List时提供了我想要的内容。我不认为这是真的,它可以正常工作。我的方法调用在集合中循环并作用于抽象(重写)方法和属性。我在前面的回复中使用了上面的代码,效果非常好。该项目是.NET 2.0,使用CSC.exe(C#)3.0作为编译器。我猜您在运行该项目时遇到了困难?:)这和我给你的答案是一样的……从技术上讲,这也是你最初问的问题的答案!:)