Linq“Select”合理性问题

3

我有类似下面代码的逻辑。看起来,为了检查空引用,我必须有两个单独的Select语句。Linq高手能告诉我如何改进这样的查询吗?

List<C> cList = Globals.GetReferences(irrelevantThing) // GetReferences returns List<A>, which are references to B
            .Select(a => a.GetB()) // GetB returns type B, can be null
            .Where(b => b != null && someOtherConditions)
            .Select(c => new C(b)) // C Constructor cannot have a null parameter
            .ToList();

谢谢。

编辑:稍微整理了示例代码。

2个回答

5

首先,我会更改参数名称 - 在第一个 Select 之后,你有一个 B,那么为什么不把它称为 b

List<B> bList = Globals.GetReferences(irrelevantThing)
            .Select(a => a.GetB()) // GetB returns type B, can be null
            .Where(b => b != null && someOtherConditions)
            .Select(b => new B(b))
            .ToList();

在那时,我不得不想知道为什么你还需要第二个 Select ... 你已经有了一个 B,那你为什么还要创建一个新的呢?B(B old) 构造函数是做什么的?
如果你确实需要另一个 select,那么对我来说似乎没有问题。我的意思是,如果 GetB 很便宜,你总是可以使用:
List<B> bList = Globals.GetReferences(irrelevantThing)
            .Where(a => a.GetB() != null && someOtherConditions)
            .Select(a => new B(a.GetB()))
            .ToList();

……但说实话,我不确定我会这样做。


我稍微修改了例子- 它有点偏离了。希望这样能澄清事情。 - raynjamin
我同意Jon的观点。就我个人而言,如果GetB很便宜,我会使用“where first”方法。我不知道执行上是否有任何区别,因为Linq语句已经被编译和优化了,但在我看来,这种方法更加简洁。 - rybosome
@raynjamin:好的,那我认为现在这样就可以了。 - Jon Skeet
@Ryan:执行取决于涉及的LINQ提供程序类型。鉴于OP谈论了List<T>,它将是面向对象的LINQ - 因此,随着额外的Select,在每次迭代中将涉及一个额外的层。 - Jon Skeet

2

我认为使用查询语法和let运算符会更加美观:

   var queryB = from a in Globals.GetReferences(irrelevantThing)
                let b = a.GetB()
                where b != null && someOtherConditions
                select new B(b);

   var bList = queryB.ToList()

根据您的偏好而定...

顺便提一下,在扩展方法语法中,上述内容可以翻译为

   var queryB = Globals.GetReferences(irrelevantThing)
            .Select(a => new { a, b = a.GetB() })
            .Where(x => x.b != null && someOtherConditions)
            .Select(x => new B(x.b))
            .ToList();

更新:刚刚意识到您还可以使用select into子句按原始查询文字逐字翻译:

   var queryB = from a in Globals.GetReferences(irrelevantThing)
                select a.GetB() into b
                where b != null && someOtherConditions
                select new B(b);

虽然仍然喜欢使用let...


虽然我对 @jonskeet 表示敬意,但我认为这个回答非常好。我同意在这种情况下查询语法看起来更加优美。 - raynjamin
使用 select into 添加了另一种可能性。 - jeroenh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接