【问题标题】:Why does ReSharper suggest I convert a for loop into a LINQ expression?为什么 ReSharper 建议我将 for 循环转换为 LINQ 表达式?
【发布时间】:2012-03-05 16:07:44
【问题描述】:

在 Visual Studio Re-Sharper 中不断建议我将 for 循环转换为 linq 表达式,但这是什么原因?

哪个更快?

以下是一些示例循环,其中 resharper 建议进行 linq 转换:

foreach (XmlNode legendEntryNode in _legendEntryNodes)
{
    var xmlElement = legendEntryNode["FeatureType"];

    if (xmlElement == null || !xmlElement.InnerText.Equals(featuretype)) continue;

    var xmlNodeList = legendEntryNode.SelectNodes("Themes/Theme");

    if (xmlNodeList != null)

    foreach (XmlNode themeNode in xmlNodeList)
    {
        var element = themeNode["Value"];

        if (element == null || !element.InnerText.Equals(v)) continue;

        var xmlElement1 = themeNode["Icon"];

        if (xmlElement1 != null)
        {
            string iconname = "<ms:ICON>" + xmlElement1.InnerText + "</ms:ICON>";

            var element1 = themeNode["Highlight"];

            if (element1 != null)
            {
                string highlightname = "<ms:HIGHLIGHT>" + element1.InnerText + "</ms:HIGHLIGHT>";
                gml = gml.Insert(c, iconname + highlightname);

                c += (iconname.Length + highlightname.Length);
            }
        }
        break;
    }
}

还有这个更简单的例子:

for (int i = 0; i < getPointsRequest.Attribs.Length; i++)
{
    string attribName = getPointsRequest.Attribs[i].AttributeName;

    if (!String.IsNullOrEmpty(attribName))
    {
        sqlQuery += "<ms:" + attribName + ">||\"" + attribName + "\"||</ms:" + attribName + ">";
    }
}

【问题讨论】:

  • 您可能想向我们展示一个示例循环。
  • 只是一件小事,我知道这些是示例,但您可能希望将字符串连接更改为string.Format,因此简单示例变为:sqlQuery += string.Format("&lt;ms:{0}&gt;||\"{0}\"||&lt;/ms:{0}&gt;", attribName);,更易于阅读。 Resharper 可以轻松更改它们,因为它是它的重构选项之一。
  • (顺便说一句,代码格式的反引号在问题标题中不起作用,很遗憾)
  • 您可能还想使用 StringBuilder 而不是“sqlQuery +=”字符串连接。

标签: c# linq for-loop resharper


【解决方案1】:

速度通常与大部分代码无关 - 您应该以最简单的方式编写代码,然后对其进行测量以确保它足够快。 p>

如果您的 for 循环真的只是查询,那么 LINQ绝对 是获得更易读代码的好方法。它不是普遍适用的,但您至少应该牢记经常。

通常可以将 for 循环转换为要延迟评估的查询,然后是 foreach 循环,该循环对查询返回的每个值执行一些操作。这有助于将这两个方面分开,让您在阅读代码时一次只专注于一个方面。重要的是保持 LINQ 查询 查询,而不是在其中使用副作用 - 它被设计为具有一种功能性方法,它确实不会与副作用很好地混合。

如果你有一些具体的例子,我们可以就哪些循环转换为使用 LINQ 有意义,哪些没有意义提供更多意见。

【讨论】:

  • 我会假设,虽然简单循环的速度可能看起来无关紧要,但所有这些不相关的地方肯定会在总体方案中产生巨大的性能差异?
  • @CSharpened:这是一个很大的假设,你应该在尝试对任何地方进行微优化之前验证它。通常,架构和整体设计对性能的影响远大于单个代码位,瓶颈也经常出现在 IO 而非处理中。您应该确定您的性能要求是什么,测量满足您需求的最清晰代码的性能,然后如果您需要优化,请使用分析器以有针对性的方式进行。我当然不会假设所有代码区域都对整体性能做出统一贡献。
  • 好的,谢谢。欣赏它。与许多开发人员相比,作为一个相对较新的开发人员,我有时会忽略这样的事情,因为我经常负责项目的一小部分,因此希望确保我的部分尽可能顺利和快速地运行,同时仍然 100% 满足要求。
  • @CSharpened:如果您在一个更大的团队中工作,您应该询问您的团队成员对您的项目部分的性能要求是什么。他们可能没有考虑到这一点 - 您应该委婉地建议对整个系统进行基准测试会很有用,并在整体性能不令人满意时分析哪些区域是瓶颈。
  • 哦,我确实使用它,但是我仍然经常使用 for/foreach 循环,尤其是对于低级别的东西。我敢肯定大多数 C 程序员和我相似,他们中的大多数人可能从未接触过 java/C#,所以他们可能甚至不知道他们是否可读,更不用说他们了。
【解决方案2】:

这样没有性能提升,但有一些好处

  • 使代码更具可读性。
  • 减少行数。
  • 易于维护。
  • 在某些情况下,您不需要临时变量,而 for 循环中可能需要这些变量。使用 Linq,您可以链接查询。

更多详情可以参考:

希望对你有所帮助。

【讨论】:

  • 人们更愿意编写更接近自然语言的代码......显然,LINQ 有助于这样做......
【解决方案3】:

速度上可能没有差异,但是使用 Linq 通常会产生更简洁的代码。 这并不是说您应该始终接受 R# 转换为 Linq 表达式的建议。有时复杂但易于理解的 foreach 循环会转换为有效但不易理解的 Linq 表达式。

【讨论】:

  • 从技术上讲,for 循环总是更快,因为 linq 表达式需要方法调用。
  • 这是我遇到的主要问题之一。我对 linq 并没有真正了解,因此我发现一些转换后的代码难以阅读,这实际上与 resharper 最有可能想要的效果相反。我怀疑这对于其他不使用 linq 的开发人员来说也是一样的,并且可能会使我的部分代码难以被那些没有跟上 linq 速度的人阅读。
  • linq 的全部意义在于使用更简洁、更易读的代码——在某些情况下它可能更简洁,要么是例外情况,要么是读者无法理解函数式/声明性代码。您基本上永远不想将这样的 linq 代码编写为 foreach 循环: from s in selection.ShapeRange.Cast() where s.IsSomething() select s.Name
【解决方案4】:

一般来说,ReSharper 的建议只是建议,没有警告。因此,您可以自行决定采用哪种方式:LINQ 还是 foreach。
我对建议“使用'var'”有同样的问题。只有当我认为读者可以更好地阅读该声明时,我才会点击该建议。
在编写代码时,可读性是我的首要任务之一。

【讨论】:

    【解决方案5】:

    我会说有时不转换是有原因的。 ReSharper 没有提供重构以将 LINQ 表达式(返回)转换为 for 循环,这可能不太令人钦佩。我有几次将循环转换为表达式,然后想在循环中放入一些进一步的操作(通常是调试操作);我必须手动将它们转换回来。

    我会警告不要在没有充分理由的情况下转换 for 循环。很多时候它确实并没有提高可读性,而且没有任何其他强有力的理由这样做(正如其他人正确指出的那样,大多数循环对速度不是很关键)。

    我认为一些 for 循环比 LINQ 等价物更具可读性,因为它们在视觉上将循环的动作分解成小块。我会说它往往是小循环(三或四行),通过将它们变成一行的表达式来得到最大的改进。

    [对不起,这篇文章主要是意见,但可读性是一个主观主题。不要拖钓!]

    【讨论】:

      【解决方案6】:

      嗨,Linq 实际上是在内部调用一个 for 循环。我想归结为 Linq 表达式通常更容易阅读/维护。如果您真的关心性能,可以将两者进行很好的比较:http://geekswithblogs.net/BlackRabbitCoder/archive/2010/04/23/c-linq-vs-foreach---round-1.aspx

      【讨论】:

        【解决方案7】:

        作为其他人的参考,这里是 Resharper 建议的 for 循环和 for 循环的示例

        for (int x = 0; x < grid.Length; x++)
                {
                    var intCount = grid[x].Select((a, b) => new {Value = a, Index = b})
                        .GroupBy(y => y.Value)
                        .Where(y => y.Count() > 1).Select(item => item.Key).ToArray();
        
                    if (intCount.Count() > 1)
                        return false;
                }
        

        为了解释这段代码,这个 for 循环将获取数组中的所有重复项。获取所有重复项后,检查项数是否大于 1,然后返回 false。

        这是 LINQ 中建议的 for 循环:

          return grid.Select(t => t.Select((a, b) => new {Value = a, Index = b}).
                    GroupBy(y => y.Value).Where(y => y.Count() > 1).
                    Select(item => item.Key).ToArray()).All(intCount => intCount.Count() <= 1);
        

        可能没有性能提升,但是从示例中可以看出,LINQ 查询更干净、易于阅读、行数更少(在这种情况下,只有一行代码,我只是在粘贴后对其进行了调整在这里)并且也易于调试。

        【讨论】:

          猜你喜欢
          • 2012-11-25
          • 2012-08-10
          • 2013-03-05
          • 2012-10-07
          • 2013-10-25
          • 2019-05-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多