C#foreach vs functional each

时间:2010-01-07 22:55:25

标签: c# functional-programming

您更喜欢哪一个?

foreach(var zombie in zombies)
{
    zombie.ShuffleTowardsSurvivors();
    zombie.EatNearbyBrains();
}

zombies.Each(zombie => {
    zombie.ShuffleTowardsSurvivors();
    zombie.EatNearbyBrains();
});

8 个答案:

答案 0 :(得分:26)

第一个。出于某种原因,这是语言的一部分。

就个人而言,如果有充分的理由,我只会使用第二种功能方法进行流控制,例如在.NET 4中使用Parallel.ForEach。它有许多缺点,包括:

  • 速度慢。它将在每个元素上引入一个委托调用,就像你foreach (..) { myDelegate(); }
  • 一样
  • 这是非标准的,因此大多数开发人员会更难理解
  • 如果你关闭任何本地人,你将迫使编译器进行关闭。如果涉及线程,这可能会导致奇怪的问题,并且会给组件增加完全不必要的膨胀。

我认为没有理由为语言中已存在的流控制结构编写自己的语法。

答案 1 :(得分:10)

这里你正在做一些非常必要的事情,比如编写一个语句而不是一个表达式(可能是Each方法没有返回任何值)和变异状态(只能假设这些方法,因为它们也是似乎没有返回值)但是你试图通过将一组语句作为委托传递来将它们作为“函数式编程”传递出去。这段代码几乎不能远离函数式编程的理想和习语,那么为什么要试着把它伪装成呢?

尽管我喜欢C#这样的多范式语言,但我认为当范式在更高层次上混合时(例如,以功能或命令式风格编写的整个方法),它们最容易理解和维护,而不是当多个范例在单个语句或表达式中混合时。

如果您正在编写命令性代码,请诚实地使用它并使用循环。没什么值得羞耻的。命令式代码本质上不是坏事。

答案 2 :(得分:5)

第二种形式。

在我看来,你必须使用的语言结构和关键词越少越好。 C#中有足够多的外来瑕疵。

通常,您输入的越少越好。说真的,你怎么不想在这样的情况下使用“var”?当然,如果明确是你唯一的目标,你仍然会使用匈牙利表示法...你有一个IDE,当你将鼠标悬停在你身上时会给你输入类型信息......当然,如果你使用的是Resharper,还是按Ctrl + Q.

@ T.E.D。委托调用的性能影响是次要问题。如果你确实这样做了一千个术语,请运行点跟踪并查看它是否不可接受。

@ Reed Copsey:非标准,如果开发人员无法解决“。每个”正在做什么,那么你会遇到更多问题,呵呵。攻击语言以使其更好是编程的一大乐趣。

答案 3 :(得分:4)

lamda版本实际上并不慢。我只是进行了快速测试,代理版本的速度提高了约30%。

这是codez:

class Blah {
    public void DoStuff() {
    }
}

        List<Blah> blahs = new List<Blah>();
        DateTime start = DateTime.Now;

        for(int i = 0; i < 30000000; i++) {
            blahs.Add(new Blah());
        }

        TimeSpan elapsed = (DateTime.Now - start);
        Console.WriteLine(string.Format(System.Globalization.CultureInfo.CurrentCulture, "Allocation - {0:00}:{1:00}:{2:00}.{3:000}",
         elapsed.Hours,
         elapsed.Minutes,
         elapsed.Seconds,
         elapsed.Milliseconds));

        start = DateTime.Now;

        foreach(var bl in blahs) {
            bl.DoStuff();
        }

        elapsed = (DateTime.Now - start);
        Console.WriteLine(string.Format(System.Globalization.CultureInfo.CurrentCulture, "foreach - {0:00}:{1:00}:{2:00}.{3:000}",
         elapsed.Hours,
         elapsed.Minutes,
         elapsed.Seconds,
         elapsed.Milliseconds));

        start = DateTime.Now;

        blahs.ForEach(bl=>bl.DoStuff());

        elapsed = (DateTime.Now - start);
        Console.WriteLine(string.Format(System.Globalization.CultureInfo.CurrentCulture, "lambda - {0:00}:{1:00}:{2:00}.{3:000}",
         elapsed.Hours,
         elapsed.Minutes,
         elapsed.Seconds,
         elapsed.Milliseconds));

好的,所以我运行了更多测试,结果就是这里。

  1. 执行的顺序(forach,lambda或lambda,foreach)没有太大区别,lambda版本仍然更快:

    foreach - 00:00:00.561
    lambda - 00:00:00.389
    
    lambda - 00:00:00.317
    foreach - 00:00:00.337
  2. 对于类的数组,性能差异要小得多。以下是Blah [30000000]的数字:

    lambda - 00:00:00.317 
    foreach - 00:00:00.337
  3. 这是相同的测试,但Blah是一个结构:

    Blah[] version 
    lambda - 00:00:00.676 
    foreach - 00:00:00.437 
    
    List version:
    lambda - 00:00:00.461
    foreach - 00:00:00.391
  4. 优化构建,Blah是一个使用数组的结构。

    lambda - 00:00:00.426
    foreach - 00:00:00.079
  5. 结论:对于foreach vs lambda的表现没有全面的答案。答案是取决于Here是对List<T>进行更科学的测试。据我所知,它非常高效。如果您真的关心性能使用for(int i...循环。为了迭代一千个客户记录的集合(例子),这真的无关紧要。

    至于决定使用哪个版本,我会在lambda版本的底部放置潜在的性能。

    结论#2 T[](其中T是值类型)在优化的构建中,foreach循环的速度大约是此测试的5倍。这是Debug和Release构建之间唯一的重要区别。所以你去,对于值类型的数组使用foreach,其他一切 - 这没关系。

答案 4 :(得分:1)

This question包含一些有用的讨论,以及关于该主题的哲学方面的MSDN博客文章的链接。

答案 5 :(得分:1)

我认为扩展方法很酷,但我认为break和编辑并继续更酷。

答案 6 :(得分:0)

我认为第二种形式更难以优化,因为对于这一次调用,编译器无法以任何其他方式调用每个方法调用循环。


既然有人问我,我会详细说明。该方法的实现很容易与调用它的代码分开编译。这意味着编译器并不确切知道要执行多少循环。

如果您使用“foreach”表单,则在创建循环代码时,可能可以使用该信息(它也可能不可用,在这种情况下没有区别)

例如,如果编译器碰巧知道(来自同一文件中的先前代码)列表中恰好有20个项目,它可以用20个引用替换整个循环。

但是,当编译器在其源文件中为“Every”方法创建代码时,它不知道调用者列表的大小。它必须支持任何规模。它能做的最好的事情就是尝试为其CPU找到某种最佳的展开方式,并添加额外的代码来循环 ,如果它对于展开而言太小,则进行适当的循环。对于典型的小循环,这甚至可能最终更慢。当然,对于小循环,你并不在乎......除非它们碰巧在一个大循环中。

正如另一张海报所提到的,这是(并且应该是)次要问题。重要的是哪个更容易阅读和/或维护,但我没有看到那里的巨大差异。

答案 7 :(得分:-4)

我也不喜欢,因为我认为不需要使用'var'。我写的是:

foreach(Zombie zombie in zombies){
}

但至于功能还是预告,对我来说,我绝对更喜欢foreach,因为后者似乎没有充分的理由。