时间:2019-03-17 标签:c#foreachwithAction.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
,所以我几乎无法克隆
它。 问题是,当我对 c.WriteMessage
执行 Invoke
时,由于执行被延迟,它通常不会在列表中的第一对上触发,并且会有时实际上只在最后一个项目上发射一大堆。
我知道这与 c 作为引用在 Invoke
实际被调用之前发生变化有关,但有没有办法避免这种情况?
执行一般的 for(int i=0 etc
循环似乎无法解决此问题。
有人知道如何解决此问题吗?
记住,不能克隆
客户端
。
Alright, so I'm having a bit of an issue here.
Here is the loop.
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));
}
}
}
Here is LazyAsync
public static class LazyAsync
{
public static void Invoke(Action a)
{
a.BeginInvoke(a.EndInvoke, null);
}
}
Each Client
contains a socket
, so I can't hardly Clone
it.
The problem is, when I do the Invoke
to c.WriteMessage
, since the execution is delayed, it usually won't fire on the first couple in the list, and will sometimes actually only fire a whole bunch on the very last item.
I know this has to do with c being a reference that changes before Invoke
actually gets called, but is there a way to avoid this?
Doing a general for(int i=0 etc
loop doesn't seem to fix this issue.
Anyone have any ideas on how I can fix this?
Remember, can't Clone
Client
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
将您的
c
复制到本地变量,如下所示:如果您想获取更多信息,请在网络上搜索:“访问修改后的闭包”。
Copy your
c
to local variable like this:Do a web search for: "Access to modified closure" if you want to get more information.
您的怀疑是正确的:变量
c
被 lambda 表达式捕获,但直到稍后才进行评估。每当您在 lambda 表达式中使用循环变量时,就会弹出这种错误,因为循环变量的作用域是在循环之外,而不是在循环的每次迭代中。
您可以通过在
foreach
循环中创建一个新的局部变量,为其分配c
,然后将该新的局部变量传递到 lambda 表达式来解决此问题:一些相关的 StackOverflow 帖子:
Your suspicion is right: the variable
c
is captured by the lambda expression, but not evaluated until later.This flavor of error pops up whenever you make use of a loop variable within a lambda expression, since the loop variable is scoped outside the loop, and not with each iteration of the loop.
You can work around this by creating a new local variable in the
foreach
loop, assignc
to it, and then pass that new local variable into the lambda expression:Here are a few related StackOverflow posts:
尝试将
c
设置为局部变量并对其调用LazyAsync.Invoke
,以避免c
被foreach 在调用发生之前循环。当
LazyAsync.Invoke
执行c.WriteMessage
时,它会在c
现在指向的任何内容上调用WriteMessage
,而不是评估LazyAsync.Invoke(() => c.WriteMessage(sm))
时的情况Try setting
c
to a local variable and callingLazyAsync.Invoke
on that, to avoidc
being reassigned to by theforeach
loop before the invoke happens. WhenLazyAsync.Invoke
doesc.WriteMessage
, it's callingWriteMessage
on whateverc
happens to now point to, not what it was whenLazyAsync.Invoke(() => c.WriteMessage(sm))
was evaluated