这还算是一个闭包吗?

3

testit()方法是一个闭包。虽然aString已经超出了范围,但testit()仍然可以在其上执行。testit2()正在使用一个没有超出范围(mystring)的变量,但它也没有被传递到testit2()中。testit2()是否被认为是闭包?

string mystring = "hello world";
Action testit = new Action(delegate { string aString = "in anon method"; Debug.WriteLine(aString); });
testit();

//capture mystring.  Is this still a closure?
Action testit2 = new Action(delegate { Debug.WriteLine(mystring); });
//mystring is still in scope
testit2();

在第二个例子中,mystring可以在方法外部进行更新,并且这些更改将反映在testit2()中。这与普通方法的行为不同,普通方法只能将mystring作为参数捕获。
3个回答

6

这两个示例都是匿名函数。第二个示例使用闭包来捕获局部变量。变量的作用域寿命与匿名函数无关,是否创建闭包来使用它。只要变量在匿名函数外定义并在其中使用,就会创建闭包。

第一个匿名函数不使用本地状态,因此不需要闭包。它应该编译成静态方法。

这是必要的,因为匿名函数可以存在于当前函数的生命周期之外。因此,在以后执行委托时,必须捕获所有在匿名函数中使用的本地变量。


1
它们是匿名方法,至少在C#术语中是这样的。不过,无论是lambda表达式还是匿名方法都被视为匿名函数。 - Jon Skeet
我觉得跟微软的人挑剔术语有点不好意思 :) - Jon Skeet
@Jon,欢迎挑剔。这是学习新知识的又一次机会。我不知道匿名函数是这两种不同情况的通用术语。我已经开始在任何地方称它们为lambda了。但是,匿名函数打字更困难一些 ;) - JaredPar

3

闭包不会捕获作用域中的值,而是捕获作用域的实际定义。因此,任何其他具有对相同作用域的引用的代码都可以修改其中的变量。


这种闭包被称为“词法闭包”-它捕获了词法作用域。 - yfeldblum

1

testit 并不像 testit2 那样具有闭包性,因为它仅仅使用了一个本地定义的变量,而不是“父”环境中的变量(如 mystring)。

然而,我认为两者都是闭包,因为它们都能够通过匿名方法从其封闭的环境中捕获变量。


谢谢。我正在看你在这里的示例:https://dev59.com/InRC5IYBdhLWcg3wCMrX。counter就像testit()定义aString一样被定义。我认为这意味着你给出的示例并不是闭包最强的案例,而这似乎是你对testit()所陈述的。 - 4thSpace
@4thspace:不是的,请再读一遍例子。计数器是在匿名方法之外定义的,更像是我的字符串。 - Jon Skeet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接