static void Main(string[] args)
{
var s = 3;
Func<int, Func<int>> func =
x => () =>
{
return x;
};
var result1 = func(s);
func = null;
s = 5;
var result2 = result1();
Console.WriteLine(result2);
Console.ReadKey();
}
我的理解是 x 实际上并未声明为变量,例如。 var x = 3。相反,它被传递给外部函数,该函数返回一个返回原始值的函数。在返回 this 时,它围绕 x 创建一个闭包以记住它的值。之后,如果你改变 s,它就没有效果。
这样对吗?
(顺便说一句,输出是 3,这是我所期望的)。
编辑:这是我认为的原因的图表
x=3 被传递给 func,它返回一个只返回 x 的函数。但是x在内部函数中是不存在的,只有它的parent,我把它设为null后它的parent已经不存在了。当运行内部函数时,x 存储在哪里?它必须从父级创建一个闭包。
进一步说明:
int s = 0;
Func<int, Func<int>> func =
x => () =>
{
return x;
};
for (s = 0; s < 5; s++)
{
var result1 = func(s);
var result2 = result1();
Console.WriteLine(result2);
};
输出为 0, 1, 2, 3, 4
但是对于你的例子:
static void Main(string[] args)
{
int s = 0;
Func<int, Func<int>> func =
x => () =>
{
return s;
};
List<Func<int>> results = new List<Func<int>>();
for (s = 0; s < 5; s++)
{
results.Add(func(s));
};
foreach (var b in results)
{
Console.WriteLine(b());
}
Console.ReadKey();
}
输出为 5 5 5 5 5,这不是您想要的。它没有捕获变量的值,它只是保留了对原始 s 的引用。
在 javascript 中创建闭包正是为了避免这个问题。
最佳答案
不,这不是 s
上的闭包,x
只是生成委托(delegate)的 lambda 表达式的参数(实际上可以简化为 x => () => x
.
Func<int, Func<int>> func = x => () => x;
var a = func(3);
var b = func(5);
Console.WriteLine(a());
Console.WriteLine(b());
您将按预期获得 3
和 5
。在这两种情况下,它实际上都不会记住其他时间的 x
,但它确实在外部 lambda 的持续时间内在本地关闭了 x
。
基本上,每次调用 x => () => x
都会创建一个新的 () => x
委托(delegate),它捕获 x 的本地值
(不是传入的 s
)。
即使您使用 s
并将其传入并更改它,您仍然会得到 3
和 5
:
int s = 3;
Func<int, Func<int>> func = x => () => x;
var a = func(s);
s = 5;
var b = func(s);
// 3 and 5 as expected
Console.WriteLine(a());
Console.WriteLine(b());
现在,它确实在局部函数内捕获了局部变量x
,它在每个 打电话。因此 x
不会在较大的 lambda 调用之间持续存在,但如果稍后在 lambda 中发生更改,它将被捕获。
例如,假设您有这个:
int s = 3;
Func<int, Func<int>> func = x =>
() => {
Func<int> result = () => x;
x = 10 * x;
return result;
};
var a = func(s);
s = 5;
var b = func(s);
在这种情况下,匿名方法中x
上的闭包更加明显。运行结果将是 30 和 50,因为在匿名方法中对 x
的修改会影响该匿名方法本地 x
上的闭包,但是,这些不携带在调用之间结束,因为它只捕获传递给匿名方法的本地 x
,而不是用于调用它的 s
。
因此,总而言之,在您的图表和示例中:
* main 将 s
传递给更大的 lambda(图中的 func)
* func 在调用生成匿名方法 () => x
x
上关闭
一旦调用了外部 lambda (func),closer 就开始和结束了,因为它仅对该 lambda 是本地的,不会关闭来自 main 的任何内容。
这有帮助吗?
关于c# - 这是 C# 中的闭包示例吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10998960/