鉴于:
void AFunction()
{
foreach(AClass i in AClassCollection)
{
listOfLambdaFunctions.AddLast( () => { PrintLine(i.name); } );
}
}
void Main()
{
AFunction();
foreach( var i in listOfLambdaFunctions)
i();
}
Run Code Online (Sandbox Code Playgroud)
现在你会认为这样做会对等:
void Main()
{
foreach(AClass i in AClassCollection)
PrintLine(i.name);
}
Run Code Online (Sandbox Code Playgroud)
但它没有,它将做的是每次打印AClassCollection中最后一项的名称!所以基本上每个lambda函数都使用相同的项目.我怀疑"当lambda被创建时"或"当它使用其中使用的外部变量的快照时"可能会有一些延迟,或者基本上只是持有'对局部变量的引用'i'
所以我这样做了:
string astr = "a string";
AFunc fnc = () => { System.Diagnostics.Debug.WriteLine(astr); };
astr = "changed";
fnc();
Run Code Online (Sandbox Code Playgroud)
而惊喜,惊喜,它输出"改变了!"
我正在使用XNA 3.1(无论是什么c#)
到底是怎么回事?lambda函数以某种方式存储变量或其他东西的"引用"吗?反正这个问题呢?
Chr*_*ter 17
这是一个修改过的闭包
请参阅:类似问题,例如Access to Modified Closure
要解决此问题,您必须在for循环的范围内存储变量的副本:
foreach(AClass i in AClassCollection)
{
AClass anotherI= i;
listOfLambdaFunctions.AddLast( () => { PrintLine(anotherI.name); } );
}
Run Code Online (Sandbox Code Playgroud)
Eri*_*ert 14
lambda函数以某种方式存储变量或其他东西的"引用"吗?
关.lambda函数捕获变量本身.不需要存储对变量的引用,事实上,在.NET中永久存储对变量的引用是不可能的.您只需捕获整个变量.您永远不会捕获变量的值.
请记住,变量是存储位置.名称"i"指的是特定的存储位置,在您的情况下,它始终指的是相同的存储位置.
反正这个问题呢?
是.每次循环创建一个新变量.然后闭合每次捕获一个不同的变量.
这是C#最常报告的问题之一.我们正在考虑更改循环变量声明的语义,以便每次通过循环创建一个新变量.
有关此问题的更多详细信息,请参阅有关此主题的文章:
http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/
到底是怎么回事?lambda函数以某种方式存储变量或其他东西的"引用"吗?
是的正是那个; c#捕获的变量是变量,而不是变量的值.你通常可以通过引入一个临时变量并绑定到它来解决这个问题:
string astr = "a string";
var tmp = astr;
AFunc fnc = () => { System.Diagnostics.Debug.WriteLine(tmp); };
Run Code Online (Sandbox Code Playgroud)
特别是在foreach臭名昭着的地方.
| 归档时间: |
|
| 查看次数: |
9909 次 |
| 最近记录: |