冻结瓶盖的优雅方法 [英] Elegant way to freeze closures
问题描述
是否有任何优雅的方法来冻结"从方法返回的操作中使用的变量?
Is there any elegant way to "freeze" the variables used in an action that is returned from a method?
只需看下面的代码:
static void Main(String[] args)
{
foreach(Action a in ClosureTrap("a", "b"))
{
a();
}
}
static List<Action> ClosureTrap(params String[] strings)
{
List<Action> result = new List<Action>();
foreach(String s in strings)
{
result.Add(() => Console.WriteLine(s));
}
return result;
}
此代码将向控制台写入两行,均包含"b".这样做的原因并不难找到:ClosureTrap中"s"的最后一个值为"b".
This code will write two lines to the console, both containing "b". The reason for this is not too hard to find: The last value for "s" in ClosureTrap is "b".
是否有任何优雅的方法来获得两行"a"和"b"作为控制台上的输出?
Is there any elegant way to get two lines "a" and "b" as output on the console?
当前,我正在使用其他方法来创建委托.但是通过这样做,这些封盖就失去了许多优雅之处:
Currently I am using an additional method to create the delegate. But by doing this, the closures loose a lot of their elegance:
static List<Action> ClosureTrap(params String[] strings)
{
List<Action> result = new List<Action>();
foreach(String s in strings)
{
result.Add(Freeze(s));
}
return result;
}
static Action Freeze(String s)
{
return () => Console.WriteLine(s);
}
有更好的方法吗?
推荐答案
没有通用的 方法-但是,如果您仅受 specific 问题困扰的 foreach
,则有两个选项:
There's no general way to do this - but if you're only bothered by the specific issue of foreach
, then there are two options:
- 开始使用C#5编译器(您不需要定位.NET 4.5或类似的东西).关于捕获的
foreach的规则
C#5的迭代变量更改为(健全). -
如果您使用C#3或4,请捕获在循环中声明的局部变量 :
- Start using a C# 5 compiler (you don't need to target .NET 4.5 or anything like that). The rules around captured
foreach
iteration variables changed (to sane ones) for C# 5. If you're stuck with C# 3 or 4, capture a local variable declared in the loop:
foreach(String s in strings)
{
string copy = s;
result.Add(() => Console.WriteLine(copy));
}
这样,循环的每次迭代都会捕获一个单独的变量,该变量永远不会更改值.
That way each iteration of the loop captures a separate variable, which never changes value.
这篇关于冻结瓶盖的优雅方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!