如何在C#中将List <baseclass>转换为List <childclass>?</childclass> </baseclass>

时间:2013-09-27 00:02:54

标签: c# list .net

说我有以下课程:

public class BaseClass {
    ...
}

public class ChildClass : BaseClass {
    ...
}

如果我想在方法调用中将ChildClass的单​​个实例作为类型BaseClass传递,我可以做到这一点。

public void SomeCall(BaseClass baseClass)

....

ChildClass childClass = new ChildClass();
SomeCall(childClass);  <-- Works fine

但是,如果我想传入一个List,我似乎无法正确地投射它。

public void SomeCall(List<BaseClass> baseClasses) 

....

List<ChildClass> childClasses = new List<ChildClass>();
SomeCall(childClasses);  <--  Gets compiler error

我得到的错误是

Argument 1: cannot convert from 'System.Collections.Generic.List<ChildClass>'
  to 'System.Collections.Generic.List<BaseClass>'

有没有办法将列表中的值强制转换为基类的类型?

现在,我想我只需要使用foreach和AutoMap列表中的每个对象到一个新的BaseClass列表。

4 个答案:

答案 0 :(得分:2)

你最好的选择是在这里使用泛型,比如:

public void SomeCall<T>(List<T> list) where T: BaseClass
{
   foreach(T item in list)
   {
       // Assumes BaseClass defines method doSomething
       item.doSomething(....);
   }
}

调用方法做

SomeCall<ChildClass>(listOfChildren);

其他替代方案:

您可以声明您的列表,使其实际上与List<BaseClass>相关联。如,

// Assumes Children extends BaseClass
List<BaseClass> list = new List<Children>();

根据您的应用程序可能会或可能不会这样,但如果您从未使用过泛型或不能使用它们,则更容易(不确定第一部分中的语法是否有效)在.NET 4.0之下。)

答案 1 :(得分:2)

首先,您的方法是public void SomeCall(List<BaseClass> baseClasses)而不是public void SomeCall(IEnumerable<BaseClass> baseClasses)是否有任何理由?除非你特别需要它作为List<BaseClass>,比如说要添加它,你应该把它作为IEnumerable<BaseClass>传递,因为这样你就可以灵活地做到这一点:

List<ChildClass> childClasses = new List<ChildClass>();
SomeCall(childClasses.Cast<BaseClass>());

或:

List<ChildClass> childClasses = new List<ChildClass>();
SomeCall(childClasses.OfType<BaseClass>());

Cast方法将尝试将List的每个元素转换为BaseClass,如果任何强制转换失败,则会抛出,OfType方法将过滤Enumerable用于可以转换为BaseClass的实例,并且仅返回这些实例。

你不能像{Eric}一样在this answer中回答,如果List将其视为SomeCall,则可以添加内容List<BaseClass>它不是ChildClass。你可以这样做:

List<ChildClass> childClasses = new List<ChildClass>();
SomeCall(childClasses.Cast<BaseClass>().ToList());

但这确实不是一个好主意,因为你要传递的实际上是一个新的List实例。将SomeCall的参数键入为List而不是IEnumerable的唯一原因是它需要修改列表,如果您将其传递Cast<BaseClass>().ToList(),则它所做的改变将立即丢失。

如果您不打算对List进行更改,则应将其作为IEnumerable传递,并使用上述Linq方法动态投射。如果您打算进行更改,则应将列表转换为其他位置并存储,以便您可以访问这些更改。

答案 2 :(得分:0)

public interface IBaseClass
{

}
public class BaseClass : IBaseClass
{

}

public class ChildClass : BaseClass, IBaseClass {

}

public void SomeCall(IBaseClass BassClass)
{
    BassClass.Dump();
}

public void SomeCall(List<IBaseClass> BassClasses)
{
    BassClasses.Dump();
}
void Main()
{
    List<IBaseClass> _ch = new List<IBaseClass>();
    _ch.Add(new ChildClass());
    _ch.Add(new ChildClass());
    _ch.Add(new ChildClass());

    SomeCall(_ch);
}

// Define other methods and classes here

接口;这是一个LinqPad示例。

答案 3 :(得分:0)

如果您的源列表可能包含该列表包含的超类型的不同子类型,您可以使用Linq执行类似的操作:

class SuperType
{
  ...        
}
class SubType : SuperType
{
  ... 
}

static void DoSomethingInteresting( List<SuperType list )
{
  List<SubType> desired = list.Select( x => x as SubType )
                              .Where( x => x != null )
                              .ToList()
                              ;
  ...
}