C# 3.0 中匿名方法的闭包

发布于 2024-07-24 21:26:48 字数 117 浏览 8 评论 0原文

为什么匿名方法存在闭包? 为什么不直接将状态传递到方法中,而不需要通过复制闭包变量来生成新类的开销? 这难道不是“让一切全球化”的倒退吗?

有人批评我,我觉得我在这里错过了一些东西......

Why do closures exist for anonymous methods? Why not just pass state into the method without the overhead of a new class being generated with the closure variables being copied in? Isn't this just a throwback to "making everything global?"

Someone talk me down, I feel like i'm missing something here...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

一个人的夜不怕黑 2024-07-31 21:26:49

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

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

完全关闭可以非常巧妙地解决这个问题。 您真的不想弄乱匿名方法签名。

Some methods require a specific signature. For example:

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

A full closure solves this very neatly. You really don't want to mess with the anonymous methods signature.

谜兔 2024-07-31 21:26:49

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

Because the CLR takes care of it, the easiest way to "pass state into the method" is to auto-generate a class, which encapsulates that state.

无声无音无过去 2024-07-31 21:26:48

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

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

这里我们传递了两个额外的状态位到 Predicateminmax) - 但我们无法定义 List.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 之类的东西:您不想以任何其他方式执行此操作...

Purely, convenience... you don't know how much state you are going to need when defining, for example, a Predicate<T> - consider:

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

here we've passed two additional bits of state into Predicate<T> (min and max) - but we can't define List<T>.FindAll(Predicate<T>) to know about that, as that is a caller detail.

The alternative is to write the classes ourselves, but that is hard, even if we are lazy:

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

I don't know about you, but I prefer the version with the closure... especially when you consider how complex it gets when you have multiple contextual levels. I want the compiler to worry about it.

Consider also how often you use such constructs, especially for things like LINQ: you wouldn't want to have to do it any other way...

乱了心跳 2024-07-31 21:26:48

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

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

The overhead of creating a new class probably isn't something to worry about. It's just a convenient way for the CLR to make bound variables (those captured by the closure) available on the heap. They are still only accessible within the scope of the closure, so they're at all not "global" in the traditional sense.

I believe the reason for their existence is mainly convenience for the programmer. In fact, it's purely that as far as I'm concerned. You could emulate the behaviour of a closure pretty well before they existed in C#, but you don't get any of the simplicity and syntactical sugar that C# 3.0 offers. The entire point about closures is that you don't need to pass the variables in the parent scope to the function, because they're automatically bound. It's much easier and cleaner for the programer to work with, really, if you consider that the alternative is true global variables.

长安忆 2024-07-31 21:26:48

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

At least one thought is that closures exist in other languages such as javascript. So they probably included closures to be in line with people's prior experience with anonymous methods.

青春如此纠结 2024-07-31 21:26:48

因为你写这个:

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

Because you take write this:

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

And easily turn it into this

var divsor = [...]
Parallel.For(int x = 0; x < 10000000; x++, ()=> {
     source[x] = source[x] / divsor         
})
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文