【问题标题】:Nested "from" LINQ query expressed with extension methods使用扩展方法表示的嵌套“来自”LINQ 查询
【发布时间】:2012-02-02 16:09:10
【问题描述】:

如何使用扩展方法语法编写此 LINQ 查询?

var query = from a in sequenceA
            from b in sequenceB
            select ...; 

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    C# 规范的第 7.16 节回答了此表单的所有问题。

    本段回答了您的具体问题:


    一个带有第二个 from 子句的查询表达式,后跟一个 select 子句

    from x1 in e1
    from x2 in e2
    select v
    

    被翻译成

    ( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => v )
    

    所以你的查询:

    var query = from a in sequenceA            
                from b in sequenceB
                select ...;  
    

    是一样的

    var query =  ( sequenceA ) . SelectMany( a => sequenceB , ( a , b ) => ... )
    

    (请注意,这当然假定“...”是一个表达式,而不是说,一个表达式后跟一个查询继续。)

    hdv 的回答指出

    var query =  ( sequenceA ) . SelectMany( 
        a => ( sequenceB ) . Select( b => ... ) );
    

    也将是一个逻辑上有效的翻译,尽管它不是我们实际执行的翻译。在 LINQ 实现的早期,这是我们选择的翻译。然而,当你堆积更多的from 子句时,它会使 lambda 嵌套越来越深,这会给编译器带来类型推断中的巨大问题。这种翻译选择会破坏编译器的性能,因此我们引入了透明标识符机制,为我们提供了一种更便宜的方式来表示深度嵌套范围的接缝。

    如果您对这些主题感兴趣:

    要详细了解为什么深度嵌套的 lambda 会给编译器带来一个难以解决的难题,请参阅:

    http://blogs.msdn.com/b/ericlippert/archive/2007/03/26/lambda-expressions-vs-anonymous-methods-part-four.aspx

    http://blogs.msdn.com/b/ericlippert/archive/2007/03/28/lambda-expressions-vs-anonymous-methods-part-five.aspx

    有关透明标识符的更多信息,请参阅 Wes Dyer 的这篇文章,他在 C# 3.0 中实现了它们:

    http://blogs.msdn.com/b/wesdyer/archive/2006/12/22/transparent-identifiers.aspx

    还有我关于它们的系列文章:

    http://ericlippert.com/2014/07/31/transparent-identifiers-part-one/

    【讨论】:

    • 请注意,“C# 语言规范”是一个可下载的 Word 文档,因此大多数搜索引擎都不会对其进行索引,也无法在线阅读。也许微软将来会改变这一点!
    【解决方案2】:
    var query = sequenceA.SelectMany(a => sequenceB.Select(b => ...));
    

    编辑:正如 Eric Lippert 在 cmets 中指出的那样,这给出了相同的结果,但故意不是内部翻译的方式。请参阅他的答案以了解另一种致电SelectMany 的方式,该方式确实与原始方式相对应。另外,为了清楚起见,添加了省略的b =>

    【讨论】:

    • var query = sequenceA.SelectMany(a => sequenceB).Select(...); 这样的非嵌套变体也可以吗?
    • @OlivierJacot-Descombes 这也是可能的,但这意味着您不能在第二个Select 的参数中引用a
    • @hdv:你们都不对。您正确地指出,在 Olivier 的评论中,他丢失了范围变量 a。但是在您的两个翻译中,您都丢失了范围变量bb 在你的翻译中去了哪里?如果... 指的是b 怎么办?你需要另一个 lambda 在某个地方!
    • @EricLippert “b =>”是“...”的一部分,需要填写。
    • @EricLippert 我在您的回答中看到您使用另一个 SelectMany 重载编写它,但据我了解,这与我回答的含义相同。如果有错误请纠正我,我将不胜感激。
    【解决方案3】:

    另一种写法是:

    var query = a.Join(b, i => new { }, j => new { }, (i, j) => new { i = i, j = j });
    

    【讨论】:

    • 嵌套的from-statements 和SelectMany 都将嵌套的枚举展开。 IE。它们将枚举的枚举转换为一个平面枚举,其中包含源的嵌套枚举的所有元素。他们不加入两个不相关的枚举。
    • 我所做的是交叉连接,与您列出的其他选项相同。结果枚举也是平坦的。来试试吧:)。
    • 示例:输入string[][] nested = new string[][] { new string[] { "a", "b", "c" }, new string[] { "AA", "BB", "CC", "DD" }, new string[] { "1", "2", "3" }, };。预期输出:"a", "b", "c", "AA", "BB", "CC", "DD", "1", "2", "3"
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-29
    • 1970-01-01
    • 2018-12-24
    • 1970-01-01
    • 2018-11-30
    • 2021-06-12
    相关资源
    最近更新 更多