C#3.0中匿名方法的闭包

时间:2009-06-10 23:01:40

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

为什么匿名方法存在闭包?为什么不直接将状态传递给方法而不会在复制闭包变量的情况下生成新类的开销?这不仅仅是“让一切都变得全球化”的倒退吗?

有人跟我说话,我觉得我在这里错过了一些东西......

6 个答案:

答案 0 :(得分:8)

纯粹,方便......你不知道在定义时需要多少状态,例如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<T>minmax) - 但我们无法定义List<T>.FindAll(Predicate<T>)来了解这一点,因为这是一个来电者的细节。

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

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这样的事情:你不想以任何其他方式去做...

答案 1 :(得分:3)

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

我相信它们存在的原因主要是程序员的方便。事实上,就我而言,纯粹就是这样。你可以在它们存在于C#之前很好地模拟一个闭包的行为,但是你没有得到C#3.0提供的任何简单和语法糖。关于闭包的整个观点是你不需要将父作用域中的变量传递给函数,因为它们是自动绑定的。如果您认为备选方案是 true 全局变量,那么程序员使用它会更容易和更干净。

答案 2 :(得分:0)

至少有一种想法是在其他语言中存在闭包,例如javascript。因此,他们可能会将闭包与人们之前使用匿名方法的经验保持一致。

答案 3 :(得分:0)

因为你写这个:

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         
})

答案 4 :(得分:0)

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

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

完全关闭解决了这个非常整洁。你真的不想搞乱匿名方法签名。

答案 5 :(得分:-1)

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