好吧,所以我在这里遇到了一些问题。 这是循环。
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
。
答案 0 :(得分:5)
将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));
}
}
}
如果您想获得更多信息,请进行网络搜索:“访问已修改的关闭”。
答案 1 :(得分:1)
您的怀疑是正确的:变量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帖子:
答案 2 :(得分:1)
尝试将c
设置为本地变量并在其上调用LazyAsync.Invoke
,以避免在调用发生之前c
循环重新分配foreach
。当LazyAsync.Invoke
执行c.WriteMessage
时,它会在WriteMessage
现在指向的任何内容上调用c
,而不是在评估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));
}
}