中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

foreach循環對異步委托的影響

發布時間:2020-06-27 09:53:38 來源:網絡 閱讀:1417 作者:cnn237111 欄目:編程語言

在使用foreach對異步委托賦值的時候,發現一個問題。代碼如下:

static void Main(string[] args)
 {
     List<Task> lst_tsk = new List<Task>();
     List<int> lst_item = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
     foreach (var item in lst_item)
     {
         Task tsk = new Task(() =>
         {
             Console.WriteLine(item);
         });
         lst_tsk.Add(tsk);
         tsk.Start();
     }
     Console.ReadLine();
}

往Task中,賦值一個拉姆達表達式,期待運行的結果應該是1,2,3,4,5,6,7,8,9,10亂序輸出。但是實際上的結果是10,10,10,10,10,10,10,10,10,10。很多人都認為這是c#編譯器的一個bug。Eric做出了解釋,根據Eric的文章,在foreach循環語句中的變量只有一個item,該變量在循環過后,被賦值為10了。當異步線程啟動的時候,取到的item早就變成10了,因此就得出上面的結果。

根據Eric的文章,foreach只是一個語法糖,它對應的代碼如下

IEnumerator<int> e = ((IEnumerable<int>)values).GetEnumerator();
try
{
  int m; // OUTSIDE THE ACTUAL LOOP
  while(e.MoveNext())
  {
 m = (int)(int)e.Current;
 funcs.Add(()=>m);
  }
}
finally
{
  if (e != null) ((IDisposable)e).Dispose();
}

可以看到m并不包括在while語句中,而且()=>m的意思是返回當前m變量的值,而不是返回委托創建時m變量的值。因此當這個委托真正運行的時候,找到的m可能已經是其它值了。

如果把語法糖改成如下的方式:

   try 
    {
      while(e.MoveNext())  
      {  
        int m; // INSIDE  
        m = (int)(int)e.Current;  
        funcs.Add(()=>m);  
      }
}

那么m在while內部,每一個m都是單獨的。根據Eric,不這樣改的一個原因就是,它可能會增加了在循環中使用閉包的次數,(因為異步線程在啟動時,都會用到循環中的m,這個m的生命周期在while循環中,只能通過閉包機制,使得其值能夠繼續保留在內存中,能夠讓異步委托在調用的時候繼續訪問到該值)。而且,如果這樣修改了,用戶會覺得foreach每一個循環都使用了一個新的變量,而不是一個存儲了新值的舊變量。

因此,一開始的演示代碼,只需要如下修改既可以了:

        static void Main(string[] args)
        {
            List<Task> lst_tsk = new List<Task>();
            List<int> lst_item = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            foreach (var item in lst_item)
            {
var copy= item;//增加一個臨時的拷貝變量
                Task tsk = new Task(() =>
                {
                    Console.WriteLine(copy );
                });
                lst_tsk.Add(tsk);
                tsk.Start();
            }
            Console.ReadLine();
        }

這樣的話,每次委托運行的時候,都會去找copy 變量了。

可能是很多人的意見影響了C#編譯器團隊,在C#5.0中,他們決定修改這個問題,foreach循環中的變量存在于循環中,因此每次循環都使用的是一個新的變量。for循環暫時不做修正。因此,演示代碼在VS2012下,使用C#5.0的編譯器編譯,得到的結果是如預期那樣的亂序輸出。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

玛多县| 碌曲县| 历史| 唐山市| 星座| 郸城县| 永德县| 庆安县| 措美县| 柳河县| 会昌县| 定日县| 平乡县| 岱山县| 平阴县| 罗定市| 榆林市| 祁连县| 石河子市| 洮南市| 广安市| 元阳县| 左权县| 永春县| 房山区| 体育| 蓝田县| 华安县| 墨竹工卡县| 彩票| 翁源县| 乐清市| 华亭县| 临沭县| 澜沧| 博爱县| 武威市| 都昌县| 乐昌市| 体育| 海阳市|