List <base />包含不同的派生类型。如何使用LINQ安全转换?

时间:2017-06-29 02:22:57

标签: c# linq generics

我最近遇到的情况是,当我期待List<Base>时,我收到了List<Derived>,这正是我所需要的。事实证明,Derived是Base的子类,而List<Base>实际上包含了我需要的Derived对象。

但是,我收到的List是从第三方API返回的,我现在担心它最终可能会返回多个派生自Base的类型。我需要将List<Base>转换为List<Derived>,我想确保我只是转换我需要的类型,同时安全地跳过与我需要的那些无关的任何其他子类型。 / p>

例如,如果我有以下类层次结构:

public class Derived : Base {}
public class DerivedOne : Base {}
public class Base {public int i;}

然后我从以下代码得到以下结果:

static void Main(string[] args)
{
    List<Base> bList = new List<Base>() {new Derived(), new DerivedOne()};
    List<Derived> dList = new List<Derived>();
    /*InvalidCastException*/
    // dList = bList.ConvertAll(x => (Derived)x);

    /*InvalidCastException*/
    // dList = new List<Derived>(bList.Cast<Derived>());

    /*Works, but essentially 'converts' DerivedOne object
     to Derived object, which would be unwanted.*/
    dList = bList.ConvertAll(x => new Derived{i = x.i});
    // or
    dList = bList.Select(x => new Derived{i = x.i}).ToList();

    /* Works, but is there a cleaner way using LINQ? */
    dList = new List<Derived>();
    foreach(Base b in bList) {
        Derived d = b as Derived;
        if (d != null)
            dList.Add(d);
    }
}

所以,我的问题是:如何使用LINQ从List<Derived>创建List<Base>而不抛出InvalidCastException或从不相关的DerivedOne类创建Derived对象?

3 个答案:

答案 0 :(得分:4)

你可以使用

dList.Where(i=> i is Derived).ToList().ConvertAll(i => (Derived)i);

dList.OfType<Derived>().ToList()

答案 1 :(得分:0)

Ga berber,

杨磊说这是最好的答案。在框架的可维护性和可重用性方面,最好的解决方案是LINQ的OfType方法。它作为IEnumerable的扩展存在,是System.Linq命名空间的一部分。

以下是资源链接:https://msdn.microsoft.com/en-us/library/bb360913%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

修改

以下是您上面的代码:

static void Main(string[] args)
{
    List<Base> bList = new List<Base>() {new Derived(), new DerivedOne()};
    List<Derived> dList = bList.OfType<Derived>().ToList();
}

答案 2 :(得分:0)

要仅从Derived项序列中提取Base个项目,请使用Enumerable.OfType。

不同类型的序列:     IEnumerable someBaseTypes = ...     IEnumerable someDerivedTypes = ...     IEnumerable someOtherDerivedTypes = ...

混合它们。你不再是他们的类型了:

IEnumerable<Base> mixedCollection = someBaseTypes
    .Concat(someDerivedTypes.Cast<Base>())
    .Concat(someOtherDerivedTypes.Cast<Base>());

仅获取派生的。使用OfType

IEnumerable onlyDerivedTypes = mixedCollection        .OfType();

请注意,如果该集合还包含Derived的子类,那么您的结果中也会包含它们