【问题标题】:foreach(... in ...) or .ForEach(); that is the question [duplicate]foreach(... in ...) 或 .ForEach();这就是问题[重复]
【发布时间】:2011-01-14 21:22:32
【问题描述】:

可能重复:
C# foreach vs functional each

这是一个关于可读性编码的问题。

我有一个 XDocument 和一个 List<string> 元素名称,其中包含我需要屏蔽的敏感信息(在本例中替换为下划线)。

XDocument xDoc;
List<string> propertiesToMask;

这可以用两种方式编写,使用传统的foreach 循环,或者使用带有lamba 语法的.ForEach 方法。

foreach (string propertyToMask in propertiesToMask)
{
    foreach (XElement element in xDoc.Descendants(propertyToMask))
    {
        element.SetValue(new string('_', element.Value.Length));
    }
}

propertiesToMask
    .ForEach(propertyToMask => xDoc.Descendants(propertyToMask).ToList()
        .ForEach(element => element.SetValue(new string('_', element.Value.Length))));

您认为哪种方法最易读,为什么?如果您更喜欢第二个示例,您将如何呈现它以最大限度地提高可读性?

【问题讨论】:

    标签: c# lambda foreach readability


    【解决方案1】:

    传统方式有一个很大的优势,就是调试方便。但在这种情况下,我个人更喜欢ForEach() 方法。在我看来,很难调试用流利的语言编写的代码的情况仍然是可用工具的缺陷,而不是编码风格。以我个人的经验,这种方法的错误率非常低,因此问题不大。

    我会编写一些扩展方法,产生以下代码。

    propertiesToMask
       .SelectMany(property => document.Descendants(property))
       .ForEach(element => element.MaskValue());
    

    【讨论】:

    • 我更喜欢这段代码。
    • 我也喜欢流畅的界面,但是这个例子有副作用。请查看@Mehrdad 和@Reed 的帖子。
    • (几乎)所有流畅的接口都会产生副作用。我之前读过 Eric 的帖子,我理解他的观点,即不要将 ForEach() 与所有没有副作用的 LINQ 方法一起引入。但我认为这种方法本身并不坏。它有副作用。很多方法都可以。如果你习惯了这种风格,就不会有错过副作用的危险。对我来说最重要的是可读性......你能做得更好吗?即使使用 C# 以外的(假设的)语法,这对我来说似乎也接近最佳。
    • 就个人而言,我会使用 SelectMany 来生成 IEnumerable,但仍然使用传统的 foreach 来枚举设置值。
    【解决方案2】:

    这是一个非常主观的答案:

    我不太同意不喜欢 .ForEach 背后的哲学推理。也许是我缺乏计算机科学背景,我不知道。

    对我来说,第二组代码更容易阅读,看起来也不那么混乱。正如其他人所提到的,ToList() 有点不幸,但对我来说它仍然看起来更好。

    我更喜欢 Daniel Brückner 的解决方案。它似乎比其他任何一个提议的解决方案都好。

    【讨论】:

      【解决方案3】:

      第一个可以在调试器运行时更​​改,Visual Studio 允许您继续调试。更改 .ForEach 变体后,您必须重新启动调试会话并重新编译,因为它包含 lambda 表达式(VS 2008)

      【讨论】:

        【解决方案4】:

        出于三个原因,我非常喜欢第一个。

        首先,它更高效(其次,您有额外的 ToList() 调用)。

        其次,在我看来,它更具可读性。

        最后,我建议阅读Eric Lippert's blog post on this subject. 避免使用List&lt;T&gt;.ForEach 是有哲学原因的,因为它的全部目的是造成副作用,即使它具有函数式风格。

        【讨论】:

          【解决方案5】:
          foreach (string propertyToMask in propertiesToMask)
          {
              foreach (XElement element in xDoc.Descendants(propertyToMask))
              {
                  element.SetValue(new string('_', element.Value.Length));
              }
          }
          

          因为间距使扫描变得非常简单。第二个太混乱了,我必须真正阅读它。

          【讨论】:

          • 第二个在我看来还不错。更少的混乱。
          • 出于 Mehrdad 帖子中建议的原因。
          • 可读代码与高效代码同样重要(只要它不是代码异味)
          • 我发现这比充分利用 ForEach() 的实现更难阅读,而它当然更容易调试。良好使用 ForEach()(通常)意味着避免嵌套的 ForEach() 调用,而是使用 Select() 和 SelectMany()。
          【解决方案6】:

          Eric Lippert 有一个good entry about this on his blog。总而言之,ForEach 所做的任务就是产生副作用,这对于 C# 中的函数式编程可能不是一个理想的事情。

          【讨论】:

          • +1。这篇文章正是我读到这篇文章时想到的。你的总结很棒!
          猜你喜欢
          • 2021-02-24
          • 2015-09-21
          • 1970-01-01
          • 1970-01-01
          • 2023-04-01
          • 2017-10-22
          • 1970-01-01
          • 1970-01-01
          • 2023-03-29
          相关资源
          最近更新 更多