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

ast*_*003 1 c# linq generics

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

但是,我得到的 List 是从第三方 API 返回的,我现在担心它最终可能会返回不止一种派生自 Base 的类型。我需要转换List<Base>为List<Derived>并且我想确保我只转换我需要的类型,同时安全地跳过与我需要的类型无关的任何其他子类型。

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

public class Derived : Base {}
public class DerivedOne : Base {}
public class Base {public int i;}
Run Code Online (Sandbox Code Playgroud)

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Max*_*viy 5

你可以用

dList.Where(i=> i is Derived).ToList().ConvertAll(i => (Derived)i);
Run Code Online (Sandbox Code Playgroud)

或者

dList.OfType<Derived>().ToList()
Run Code Online (Sandbox Code Playgroud)

  • 第一种方法必须迭代元素两次,这会使其变慢(并且更难阅读)。 (2认同)