2016-10-27 26 views
2
我有一點問題,回調和循環

, 說我有這樣的代碼在回調中作爲引用傳遞的C#整數?

public void DoSth(Action<QueryTextureResult> result, IEnumerable<string> arr) 
{ 
    int totalData = 0; 
    foreach (var element in arr) // let's say arr.Count() is 10 
    { 
     Action<Texture> onImageReceived = (texture) => 
     { 
      if (result != null) 
      { 
       var res = new QueryTextureResult() 
       { 
        Texture = texture, 
        QueryId = queryId, 
        Index = totalData // why this one is always 10 if the callback takes time? 
       }; 

       result(res); 

       Debug.Log("INdex: " + res.Index); 
      } 
     }; 

     imageManager.GetImage("http://image.url", onImageReceived); 

     totalData++; 
    } 

} 

寫在註釋,如果我有10個元素,是需要時間的result被調用,爲什麼我收到的QueryTextureResult.Index永遠是10?它是否通過引用傳遞?有任何解決這個問題的方法嗎?

+0

變量被捕獲,它們都共享相同的內存地址。 –

回答

1

在您的代碼示例中,捕獲了totalData,因此所有代表都會引用相同的變量。在循環結束時,totalData將具有10的值,然後每個代理將讀取相同的totalData,並將得到10

解決方案是在將它傳遞給委託之前先取得變量的副本,因此每個委託都有自己的副本。

foreach (var element in arr) // let's say arr.Count() is 10 
{ 
    var copy = totalData; 
    Action<Texture> onImageReceived = (texture) => 
    { 
     if (result != null) 
     { 
      var res = new QueryTextureResult() 
      { 
       Texture = texture, 
       QueryId = queryId, 
       Index = copy // <== 
      }; 
1

這是因爲totalData是合攏和onImageReceived將異步調用。

假定有3項,它可以以下面的順序執行:

  1. onImageReceived宣佈爲項目1,其輸出totalData
  2. GetImage被稱爲項目1的
  3. totalData = 1
  4. onImageReceived申報項目2,其輸出totalData
  5. GetImage被稱爲項目2
  6. totalData = 2
  7. onImageReceived申報項目3,其輸出totalData
  8. GetImage被調用項目3
  9. totalData = 3
  10. 物品1完成後,它調用onImageReceived事件,其輸出totalData ...這是3現在
  11. 項目2完成,其中調用onImageReceived事件,並且totalData也是3
  12. 與第3項相同
+0

感謝您的回答,它現在有道理。所以我猜'索引= totalData'只有在onImageReceived被調用後纔會被填充? – andiwin

+0

@andiwinata是的。您可以設置兩個斷點:在DoSth方法的開始處和onImageReceived行動的開始處,看看會發生什麼:) –