【问题标题】:Linq mix extension and query syntaxLinq 混合扩展和查询语法
【发布时间】:2011-03-01 15:36:07
【问题描述】:

我更喜欢对基本 LINQ 操作使用扩展方法:Where()Select,但对于复杂的Select()SelectMany(),尤其是OrderBy().ThenBy() 语句,我发现查询语法更具可读性和自然。

今天我发现自己有以下查询:

from c in _myObject.ObjectsParent.ParentsEnumerable
                    .Where(c =>
                        c == anotherObject || c.Parent == anotherObject)
from q in c.MyObjectsEnumerable
orderby c.SortKey, q.Description
select new { Item = q, Text = c.Description + " -> " + q.Description };

混合查询和扩展语法是否危险(出于可读性、可维护性或任何其他原因)?

这有可能是非常主观的,如果是的话,如果它不符合一个好的主观问题的要求,我很抱歉。让我知道我是否可以改进它!

【问题讨论】:

    标签: c# linq c#-4.0


    【解决方案1】:

    混合查询和扩展语法是否危险(出于可读性、可维护性或任何其他原因)?

    我看到的最大危险是在您的代码中可能添加“惊喜”,尤其是在其他开发人员查看时。

    从编译的角度来看,查询语法直接翻译成扩展方法调用,所以这里不一定存在技术问题。但是,这可能会添加额外的方法调用,乍一看,许多开发人员并不期望这些方法调用。这可能导致潜在的可维护性问题。

    话虽如此,如果谨慎且有充分的理由,我不认为混合语法存在真正的问题。这实际上很常见——例如,如果你想用查询语法编写,但需要完全评估,它通常用括号括起来并添加 .ToList() ——或者如果你想将 PLINQ 与查询语法一起使用,它通常是 @ 987654321@,这在技术上也是混合语法......

    【讨论】:

    • 谢谢,这最直接地回答了我的大部分想法和担忧。
    【解决方案2】:

    你可以做这样的事情来让事情变得更容易。

    var firstQuery =  _myObject.ObjectsParent.ParentsEnumerable
                     .Where(c => c == anotherObject || c.Parent == anotherObject);
    
    var secondQuery = from q in firstQuery.MyObjectsEnumerable
                      orderby firstQuery.SortKey, q.Description
                      select new { Item = q, 
                                   Text = firstQuery.Description + " -> " + q.Description };
    

    现在您的查询没有混合

    【讨论】:

    • 我认为@Reed-Copsey 的意思不是(*不应该),因为 firstQuery 没有属性描述,只有它的一个元素。所以这个代码不起作用。
    【解决方案3】:

    这是一种判断要求,但许多“最佳实践”类型的问题往往是,至少一开始是这样。我的意见是,您应该在单个语句中使用其中一个。并不是为了混音中固有的任何“危险”,而是为了清晰。

    在这种特殊情况下,where 子句非常简单,我会将其重构为查询语法。

    然而,有些情况不能用查询语法优雅地表达。在无法避免混合语法的情况下,如果您将方法链拆分为自己的变量,然后在查询语法语句中简单地引用该变量,查询将(再次 IMO)更具可读性。使用你的模型:

    //The method chain can be pulled out as its own variable...
    var filteredParents = _myObject.ObjectsParent.ParentsEnumerable
                        .Where(c => c == anotherObject || c.Parent == anotherObject);
    
    //...which you can then substitute in a now purely query-syntax statement
    from c in filteredParents
    from q in c.MyObjectsEnumerable
    orderby c.SortKey, q.Description
    select new { Item = q, Text = c.Description + " -> " + q.Description };
    

    【讨论】:

      【解决方案4】:

      我不认为混合起来很危险,它认为这取决于什么更具可读性,查询语法非常可读,但没有那么灵活,所以混合一些链接似乎是一个很小的代价。我想答案是您是否认为以下完全链接的内容比您编写的内容更具可读性,我个人认为您的内容更易于阅读。

         _myObject.ObjectsParent
                  .ParentsEnumerable
                  .Where(c => c == anotherObject || c.Parent == anotherObject)
                  .SelectMany(c => c.MyObjectsEnumerable, (c, q) => new {c, q})
                  .OrderBy(t => t.c.SortKey)
                  .ThenBy(t => t.q.Description)
                  .Select(t => new {Item = t.q, Text = t.c.Description + " -> " + t.q.Description});
      

      【讨论】:

        【解决方案5】:

        我使用扩展方法,我的同事使用查询语法。没有区别。

        不过,我会说您应该将大型查询拆分为较小的查询,以便进行调试和提高可读性,因为通常没有时间成本。

        【讨论】:

          【解决方案6】:

          我自己完成了这个(虽然不是针对 .Where,而是针对 .Cast)我想说这很大程度上取决于您调用的扩展方法。

          例如我觉得完全有权使用 .Cast,因为它在语法糖 (AFAIK) 中不可用,但可能会避免使用 .Where,因为它在查询语法中有表示。

          话虽如此,我可能也会使用 .Select 来改变查询中的数据......但我有点虐待狂。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-12-24
            • 1970-01-01
            • 1970-01-01
            • 2013-05-26
            相关资源
            最近更新 更多