[英]c# foreach with Action.BeginInvoke
好吧,所以我在这里有一个问题。 这是循环。
lock (ClientLocker)
{
Trace.WriteLine("#WriteAll: " + sm.Header);
foreach (Client c in Clients)
{
if (c.LoggedIn)
{
Trace.WriteLine("#TryWriteTo[" + c.Id + "](" + sm.Header + ")");
LazyAsync.Invoke(() => c.WriteMessage(sm));
}
}
}
这是LazyAsync
public static class LazyAsync
{
public static void Invoke(Action a)
{
a.BeginInvoke(a.EndInvoke, null);
}
}
每个Client
包含一个socket
,因此我几乎无法Clone
它。 问题是,当我做Invoke
到c.WriteMessage
,因为执行被延迟,它通常会不火的第一对夫妇在列表中,并且有时实际上只火上的最后一项一大堆。
我知道这与c是在实际Invoke
之前更改的引用有关,但是有办法避免这种情况吗?
进行一般的for(int i=0 etc
循环似乎无法解决此问题。
有人对我该如何解决有任何想法吗?
记住,不能Clone
Client
。
将您的c
复制到本地变量,如下所示:
lock (ClientLocker)
{
Trace.WriteLine("#WriteAll: " + sm.Header);
foreach (Client c in Clients)
{
if (c.LoggedIn)
{
Client localC = c;
Trace.WriteLine("#TryWriteTo[" + c.Id + "](" + sm.Header + ")");
LazyAsync.Invoke(() => localC.WriteMessage(sm));
}
}
}
如果要获取更多信息,请在Web上搜索:“访问已修改的闭包”。
您的猜想是正确的:变量c
由lambda表达式捕获,但直到以后才进行评估。
每当您在lambda表达式中使用循环变量时,都会弹出这种错误提示,因为循环变量的作用域是循环外部,而不是循环的每次迭代。
您可以通过在foreach
循环中创建一个新的局部变量,为它分配c
,然后将该新的局部变量传递给lambda表达式来解决此问题:
lock (ClientLocker)
{
Trace.WriteLine("#WriteAll: " + sm.Header);
foreach (Client c in Clients)
{
if (c.LoggedIn)
{
Trace.WriteLine("#TryWriteTo[" + c.Id + "](" + sm.Header + ")");
Client copyOfC = c;
LazyAsync.Invoke(() => copyOfC.WriteMessage(sm));
}
}
}
以下是一些与StackOverflow相关的帖子:
尝试将c
设置为局部变量,并在其上调用LazyAsync.Invoke
,以避免在调用发生之前由foreach
循环将c
重新分配给c
。 当LazyAsync.Invoke
执行c.WriteMessage
,它将在c
指向的任意点上调用WriteMessage
,而不是LazyAsync.Invoke(() => c.WriteMessage(sm))
时的状态
foreach (Client c in Clients)
{
if (c.LoggedIn)
{
Trace.WriteLine("#TryWriteTo[" + c.Id + "](" + sm.Header + ")");
Client client = c;
LazyAsync.Invoke(() => client.WriteMessage(sm));
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.