Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# c foreach with Action.BeginInvoke_C#_Concurrency_Delegates_Action_Invoke - Fatal编程技术网

C# c foreach with Action.BeginInvoke

C# c foreach with Action.BeginInvoke,c#,concurrency,delegates,action,invoke,C#,Concurrency,Delegates,Action,Invoke,好吧,我这里有点问题。 这是循环 lock (ClientLocker) { Trace.WriteLine("#WriteAll: " + sm.Header); foreach (Client c in Clients) { if (c.LoggedIn) { Trace.WriteLine("#TryWriteTo[" + c.Id + "](" + sm.Header + ")");

好吧,我这里有点问题。 这是循环

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));
        }
    }
}
这是Lazyanc

public static class LazyAsync
{
    public static void Invoke(Action a)
    {
        a.BeginInvoke(a.EndInvoke, null);
    }
}
每个客户端都包含一个套接字,所以我几乎无法克隆它。 问题是,当我调用c.WriteMessage时,由于执行被延迟,它通常不会在列表中的前几项上启动,有时实际上只会在最后一项上启动一整组

我知道这与c是一个在调用调用之前更改的引用有关,但有没有办法避免这种情况

执行常规forint i=0 etc循环似乎无法解决此问题

有人知道我该怎么解决这个问题吗

请记住,无法克隆客户端。

将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表达式中使用循环变量时,就会出现这种错误,因为循环变量的作用域在循环之外,而不是循环的每次迭代

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));
        }
    }
}
您可以通过在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设置为局部变量,并对其调用lazyanc.Invoke,以避免在调用之前foreach循环将c重新分配给它。当Lazyanc.Invoke执行c.WriteMessage时,它调用的是c现在指向的任何对象的WriteMessage,而不是计算Lazyanc.Invoke=>c.WriteMessages时的状态

foreach (Client c in Clients)
{
    if (c.LoggedIn)
    {
        Trace.WriteLine("#TryWriteTo[" + c.Id + "](" + sm.Header + ")");

        Client client = c;
        LazyAsync.Invoke(() => client.WriteMessage(sm));
    }
}

几乎每天都有人问这个问题。有关此问题的一些链接和讨论,请参阅。我进行了搜索,但没有找到任何内容。并不是说我没有试过,真的;这是很难找到的。这就是为什么这个问题几乎每天都被再次提出的原因。除非你真的能从resharper那里得到修改后的关闭警告,否则你没有理由知道要搜索什么关键字。是的,我的线索已经用完了:谢谢你,这似乎是一个很简单的解决方案,我觉得有点傻,因为我没有想到它。我猜我只是假设局部变量也会发生同样的事情。谢谢。我很感激这些链接,如果能多读一些东西就好了。其中一条灰色的线,你不确定你指的是什么:p