在 linq .Select() 语句中返回不同的子类型

问题描述 投票:0回答:3

假设我在 C# 中有两个类派生自同一个基类:

class Base {}

class A: Base {}

class B: Base {}

我正在处理要投影到

Base
类型的不同子类型的对象列表。所以我做了这样的事情:

IEnumerable<Base> foo = myObjects.Select(o => {
  if(o.SomeProperty){
    return new A();
  } else {
    return new B();
  }
});

但是,这不会编译,编译器会抛出一个错误,指出它无法推断返回类型。

我的问题是:在这种情况下指定返回类型的最优雅的方法是什么?目前我已将 lambda 主体更改为:

if(o.SomeProperty){
  return new A() as Base;
} else {
  return new B() as Base;
}

这可行,但我想知道是否有更好的方法。

c# linq ienumerable
3个回答
2
投票

您的解决方案没问题,但可以通过两种方式改进:

  1. 使用三元运算符 (
    ? :
    ) 将 if-else 语句转换为表达式。
  2. as
    关键字测试表达式是否可以转换为请求的类型,如果可以则进行转换,否则返回
    null
    。这个测试在这里是多余的,因为您事先知道
    A
    B
    源自
    Base
    。使用简单的演员表代替。
IEnumerable<Base> foo = myObjects.Select(
    o => o.SomeProperty ? (Base)new A() : (Base)new B());

另一种方法是显式指定

Select
方法的泛型类型参数;但是,它要求您同时指定它们:

IEnumerable<Base> foo = myObjects.Select<SourceDataType, Base>(
    o => o.SomeProperty ? new A() : new B());

1
投票

您的解决方案很好,您还可以在 Select 扩展方法中显式点类型,如下所示:

IEnumerable<Base> foo = myObjects.Select<T, Base>(o => {
  if(o.SomeProperty)
  {
    return new A();
  } 
  else 
  {
    return new B();
  }
});

T 是您的 myObjects 集合的一种类型。


0
投票

自 C# 10 起,有一个附加选项 - 显式指定 lambda 的返回类型,这在某些情况下非常方便:

IEnumerable<Base> foo = myObjects.Select(Base (o) => {
    // ...
});
© www.soinside.com 2019 - 2024. All rights reserved.