Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/317.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语言中的奇数(循环/线程/字符串/lambda)行为#_C#_Multithreading_Loops_Closures - Fatal编程技术网

C# C语言中的奇数(循环/线程/字符串/lambda)行为#

C# C语言中的奇数(循环/线程/字符串/lambda)行为#,c#,multithreading,loops,closures,C#,Multithreading,Loops,Closures,我有一段代码,因为闭包,我认为它可以工作;然而,结果证明并非如此。这里发生了什么事情使得它不能产生预期的输出(每个单词一个) 代码: 这与闭包捕获变量本身的事实有关,在实际使用之前,闭包不会对变量进行求值。foreach循环结束后,text的值为“other”,循环结束后调用方法,调用时捕获变量text的值为“other” 详情请参阅。他解释了这种行为及其背后的一些原因。C#中的闭包在创建时没有捕获文本的价值。由于foreach循环在任何线程执行之前完成执行,因此将为每个线程指定text的最后一

我有一段代码,因为闭包,我认为它可以工作;然而,结果证明并非如此。这里发生了什么事情使得它不能产生预期的输出(每个单词一个)

代码:


这与闭包捕获变量本身的事实有关,在实际使用之前,闭包不会对变量进行求值。foreach循环结束后,
text
的值为“other”,循环结束后调用方法,调用时捕获变量
text
的值为“other”

详情请参阅。他解释了这种行为及其背后的一些原因。

C#中的闭包在创建时没有捕获文本的价值。由于foreach循环在任何线程执行之前完成执行,因此将为每个线程指定
text
的最后一个值

这可以通过以下方式进行补救:

string[] source = new string[] {"this", "that", "other"};
List<Thread> testThreads = new List<Thread>();

foreach (string text in source)
{
    // Capture the text before using it in a closure
    string capturedText = text;

    testThreads.Add(new Thread(() =>
        {
            Console.WriteLine(capturedText);
        }));
}

testThreads.ForEach(t => t.Start());
string[]source=新字符串[]{“this”、“that”、“other”};
List testThreads=new List();
foreach(源中的字符串文本)
{
//在闭包中使用文本之前捕获文本
字符串capturedText=文本;
添加(新线程(()=>
{
Console.WriteLine(capturedText);
}));
}
testThreads.ForEach(t=>t.Start());

如您所见,此代码在for循环的每个迭代中“捕获”了
text
的值。这保证了闭包在每次迭代中都会得到一个唯一的引用,而不是在迭代结束时共享同一个引用。

发生这种情况的原因是,当您开始线程时,循环已经完成,文本局部变量的值是“other”,因此当您开始线程时,将打印该值。这很容易解决:

string[] source = new string[] {"this", "that", "other"};
foreach (string text in source)
{
    new Thread(t => Console.WriteLine(t)).Start(text);
}

其他人已经解释了为什么你会遇到这个问题

幸运的是,修复非常容易:

foreach (string text in source)
{
    string textLocal = text; // this is all you need to add
    testThreads.Add(new Thread(() =>
    {
        Console.WriteLine(textLocal); // well, and change this line
    }));
}

这是捕获循环变量的典型错误。这对
for
foreach
循环都有影响:假设一个典型的构造,在整个循环期间只有一个变量。当lambda表达式或匿名方法捕获变量时,捕获的是变量本身(而不是捕获时的值)。如果更改变量的值,然后执行委托,委托将“看到”该更改

Eric Lippert在他的博客中详细介绍了这一点:

通常的解决方案是在循环内复制变量:

string[]source=新字符串[]{“this”、“that”、“other”};
List testThreads=new List();
foreach(源中的字符串文本)
{
字符串副本=文本;
添加(新线程(()=>
{
控制台写入线(副本);
}));
}
testThreads.ForEach(t=>t.Start())

这样做的原因是每个委托现在将捕获
copy
变量的不同“实例”。捕获的变量将是为循环迭代创建的变量-为该迭代分配
text
值。瞧,这一切都是可行的。

闭包/lambda无法正确绑定到foreach或循环计数器变量。将该值复制到另一个局部变量(未声明为foreach或counter变量),它将按预期工作。

我们又来了……这应该是一个编译器警告,就像在VB中一样。我认为C#团队不警告人们潜在的问题是愚蠢的。重复:@leppie,我认为这意味着我们永远找不到闭包,因为我们陷入了循环。可能的重复更具体地说,闭包只在调用时执行,而不是在声明时执行。在调用它时,Davy8所做的语句就是所发生的事情。
string[] source = new string[] {"this", "that", "other"};
foreach (string text in source)
{
    new Thread(t => Console.WriteLine(t)).Start(text);
}
foreach (string text in source)
{
    string textLocal = text; // this is all you need to add
    testThreads.Add(new Thread(() =>
    {
        Console.WriteLine(textLocal); // well, and change this line
    }));
}
string[] source = new string[] {"this", "that", "other"};
List<Thread> testThreads = new List<Thread>();
foreach (string text in source)
{
    string copy = text;
    testThreads.Add(new Thread(() =>
    {
        Console.WriteLine(copy);
    }));
}

testThreads.ForEach(t => t.Start())