【问题标题】:Closures for anonymous methods in C# 3.0C# 3.0 中匿名方法的闭包
【发布时间】:2009-06-10 23:01:40
【问题描述】:

为什么匿名方法存在闭包?为什么不直接将状态传递给方法,而无需生成新类的开销并复制闭包变量?这不只是“让一切全球化”的倒退吗?

有人劝我,我觉得我在这里遗漏了一些东西......

【问题讨论】:

    标签: c# c#-3.0 closures anonymous-methods anonymous


    【解决方案1】:

    纯粹是方便...您不知道在定义时需要多少状态,例如,Predicate<T> - 考虑一下:

    List<int> data = new List<int> {1,2,3,4,5,6,7,8,9,10};
    int min = int.Parse(Console.ReadLine()), max = int.Parse(Console.ReadLine());
    List<int> filtered = data.FindAll(i => i >= min && i <= max);
    

    在这里,我们向Predicate&lt;T&gt;minmax)传递了两个额外的状态位 - 但我们无法定义 List&lt;T&gt;.FindAll(Predicate&lt;T&gt;) 来了解这一点,因为这是调用者的详细信息。

    另一种方法是自己编写类,但这很难,即使我们很懒:

    class Finder {
        public int min, max;
        public bool CheckItem(int i) { return i >= min && i <= max;}
    }
    ...
    Finder finder = new Finder();
    finder.min = int.Parse(Console.ReadLine());
    finder.max = int.Parse(Console.ReadLine());
    List<int> filtered = data.FindAll(finder.CheckItem);
    

    我不了解你,但我更喜欢带有闭包的版本......尤其是当你考虑到当你有多个上下文级别时它会变得多么复杂。我希望编译器担心它。

    还要考虑一下您使用此类结构的频率,尤其是对于 LINQ 之类的东西:您不希望以任何其他方式这样做...

    【讨论】:

      【解决方案2】:

      创建新类的开销可能不必担心。这只是 CLR 使绑定变量(由闭包捕获的变量)在堆上可用的一种便捷方式。它们仍然只能在闭包的范围内访问,因此它们根本不是传统意义上的“全局”。

      我相信它们存在的原因主要是为了程序员的方便。事实上,就我而言,纯粹是这样。在 C# 中存在闭包之前,您可以很好地模拟闭包的行为,但是您无法获得 C# 3.0 提供的任何简单性和语法糖。关于闭包的全部要点是您不需要将父范围内的变量传递给函数,因为它们是自动绑定的。实际上,如果您认为替代方案是 true 全局变量,那么程序员的工作会更容易和更清晰。

      【讨论】:

        【解决方案3】:

        至少有一种想法是闭包存在于其他语言中,例如 javascript。因此,它们可能包含闭包,以符合人们之前使用匿名方法的经验。

        【讨论】:

          【解决方案4】:

          因为你要写这个:

          var divsor = [...]
          for(int x = 0; x < 10000000; x++){
               source[x] = source[x] / divsor         
          }
          

          并轻松将其变成这个

          var divsor = [...]
          Parallel.For(int x = 0; x < 10000000; x++, ()=> {
               source[x] = source[x] / divsor         
          })
          

          【讨论】:

            【解决方案5】:

            有些方法需要特定的签名。例如:

            public void set_name_on_click(string name)
            {
                button.Click += (s,e) => { button.Text = name; };
            }
            

            一个完整的闭包非常巧妙地解决了这个问题。您真的不想弄乱匿名方法签名。

            【讨论】:

              【解决方案6】:

              因为 CLR 会处理它,所以“将状态传递给方法”的最简单方法是自动生成一个封装该状态的类。

              【讨论】:

              • 我的意思是 CLR 会处理它,因为当编译器生成类时,它的类会处理那些被传递的变量,我想我不清楚。跨度>
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2015-02-09
              • 2010-09-17
              • 1970-01-01
              • 1970-01-01
              • 2011-12-10
              • 1970-01-01
              • 2012-05-18
              相关资源
              最近更新 更多