试图将字符串数组的元素传递给在Task.Run中调用的函数。有人知道这是什么错误吗?

这里的代码不起作用,它的行为就像从未调用过ProcessElem。

string[] arr = message.Split(new string[] {"\n"}, StringSplitOptions.None);

for (int i = 0; i < arr.Length; i++) {
    if(arr[i] != "") {
       var t = Task.Run(() => this.ProcessElem(arr[i]));
    }
 }


但是下面的代码有效

string[] arr = message.Split(new string[] {"\n"}, StringSplitOptions.None);

for (int i = 0; i < arr.Length; i++) {
    if(arr[i] != "") {
       var tmp = arr[i];
       var t = Task.Run(() => this.ProcessElem(tmp));
    }
 }


我对C#的处理方式很陌生,但是似乎这两种模式都不安全,因为调用Task.Run()的函数可能在ProcessElem函数执行之前返回,并且如果字符串通过引用传递,则它们将被销毁在调用ProcessElem之前。

如果是这种情况,将字符串传递到ProcessElem的最佳方法是什么?

另外,为什么第一个版本实际上没有“调用” ProcessElem?我在ProcessElem的顶部有一个打印语句,它仅在第二个版本中打印。

最佳答案

欢迎使用captured variables

Task.Run(() => this.ProcessElem(arr[i]))


这实质上意味着:


采取我的lambda动作:() => this.ProcessElem(arr[i])
找到/创建线程后运行它。即一段时间后。


但是,只涉及一个变量i,它是在lambda动作的作用域之外定义的,不会被复制,只是捕获和引用了同一变量。

到线程开始执行时,i的值很可能已更改。通常,循环在线程执行其工作之前完成。

这意味着到那时,i等于arr.Length,并且所有线程都尝试访问arr[arr.length],这显然会导致IndexOutOfRangeException

当您执行var tmp = arr[i];时,您将在每次循环迭代中创建一个新鲜的变量,将其复制并在lambda中捕获该副本,这就是它起作用的原因。

关于c# - C#将字符串元素数组传递到Task.Run,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52573555/

10-08 21:43