2016-10-27 9 views
2

У меня немного проблемы с обратным вызовом и для цикла, сказать, у меня есть этот кодC# integer передается как ссылка в обратном вызове?

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 является closured и 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 ... который сейчас находится сейчас
  11. Пункт 2 завершен, что вызывает событие onImageReceived, а totalData равно 3
  12. То же самое для позиции 3
+0

Спасибо за ответ, сейчас это имеет смысл. Поэтому я думаю, что 'Index = totalData' заполняется только после того, как' onImageReceived' называется? – andiwin

+0

@andiwinata Да. Вы можете просто установить две точки останова: в начале вашего метода «DoSth» и в начале действия «onImageReceived» и посмотреть, что произойдет :) –