首页 新闻 会员 周边 捐助

C# Task.Run调用外部参数奇葩问题,求高手讲解其深层的意义

0
悬赏园豆:10 [已解决问题] 解决于 2018-01-03 22:45
 1  static void Main(string[] args)
 2         {
 3             Task[] tasks = new Task[10];
 4             int[] numbers = new int[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 5             for (int i = 0; i < tasks.Length; i++)
 6             {
 7                 // int number = numbers[i];
 8                 tasks[i] = Task.Run(() =>
 9                 {
10                     Console.WriteLine("Number:{0}", numbers[i]); // 索引超出了数组界限。i会一直是10
11                     //Console.WriteLine("Number:{0}", number); //这样就正常
12                 });
13             }
14             Console.ReadLine();
15         }
问题补充:
static void Main(string[] args)
        {

            int[] numbers = new int[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            List<int> numberList = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            Dictionary<int, int> dict = new Dictionary<int, int> { { 1, 1 }, { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 } };
            HashSet<int> hashNumber = new HashSet<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

            /*全是1*/
            for (int i = 0; i < hashNumber.Count; i++)
            {
                Task.Run(() =>
                {
                    Console.WriteLine("number:{0}", hashNumber.ElementAt(0));
                });
            }

            /*无错*/
            foreach (var number in hashNumber)
            {
                Task.Run(() =>
                {
                    Console.WriteLine("number:{0}", number);
                });
            }
           

            /*输出全是5*/
            for (int i = 0; i < dict.Count; i++)
            {
                Task.Run(() =>
                {
                    Console.WriteLine("number:{0}", dict[i]);
                });
            }

            /*无错*/
            foreach (var number in numbers)
            {
                Task.Run(() =>
                {
                    Console.WriteLine("number:{0}", number);
                });
            }

            /*无错*/
            foreach (var dic in dict)
            {
                Task.Run(() =>
                {
                    Console.WriteLine("number:{0}", dic.Value);
                });
            }

            Console.WriteLine("完成");
            Console.ReadLine();
        }

经过测试,for循环的i内存地址不是独立的,所以被覆盖,foreach的item是单独分配了内存,在整个方法没有执行结束前不会销毁!SO!

PingMac的主页 PingMac | 初学一级 | 园豆:32
提问于:2018-01-03 20:49
< >
分享
最佳答案
0

这是正常的,Task.Run是在新的线程中异步执行的,在 for 循环中 Task 并不会立即执行,“i会一直是10”说明 for 循环结束后,Task 才开始执行,这时 i 的值正好是 10 。

收获园豆:10
dudu | 高人七级 |园豆:29333 | 2018-01-03 22:16

是!,恍然大悟

PingMac | 园豆:32 (初学一级) | 2018-01-03 22:45

这说明 i 的值没有被捕获到 Task 的执行上下文中,也就是说 i 变量的值不在捕获范围内,要想让 i 被捕获,需要引入中间变量,下面的代码就可以正常执行

static void Main(string[] args)
{
    Task[] tasks = new Task[10];
    int[] numbers = new int[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    for (int i = 0; i < tasks.Length; i++)
    {
        var j = i;
        tasks[i] = Task.Run(() =>
        {
            Console.WriteLine("Number:{0}", numbers[j]);
        });
    }
    Console.ReadLine();
}
dudu | 园豆:29333 (高人七级) | 2018-01-03 22:50

@PingMac: for 循环结束 i 的值就是 10

dudu | 园豆:29333 (高人七级) | 2018-01-03 22:52

@dudu: 恩,理解了,将i赋值给j,得到新的内存

PingMac | 园豆:32 (初学一级) | 2018-01-03 22:53
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册