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.相反,它被传递给外部函数,后者返回一个返回原始值的函数。在它返回时,它会在x周围创建一个闭包来记住它的值。然后,如果你改变s,它就没有效果了。
这是对的吗?
(顺便说一下输出为3,我期待)。
编辑:这是我认为为什么
的图表
x = 3传递给func,它返回一个简单返回x的函数。但是在内部函数中不存在x,只有它的父元素,并且在我使其为空后它的父元素不再存在。当内部函数运行时,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中精确创建的,以避免此问题。
答案 0 :(得分:12)
不,这不是s
上的闭包,x
只是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
委托,该委托会捕获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
的闭包,但是,这些不会在调用之间延续,因为它和#39;仅捕获传入匿名方法的本地x
,而不是用于调用它的s
。
总而言之,在您的图表和示例中:
* main 将s
传递给较大的lambda(图中的 func )
* func 在被调用以生成匿名方法时x
关闭() => x
一旦调用外部lambda(func),闭门器就会开始和结束,因为它只对那个lambda是本地的,并且不会从main接近任何东西。
这有帮助吗?
答案 1 :(得分:4)
不,改变
Func<int, Func<int>> func =
x => () =>
{
return x;
};
到
Func<int, Func<int>> func =
x => () =>
{
return s;
};
并关闭 s
变量。