2012-11-26 35 views
0

所以我想排隊一些要調用的動作。隊列<Action>調用時的參數不正確

稍微背景:嘗試使用Webclient發送請求,但是它不允許很長的URL(2000個字符以上),並且在我的系統中發現該值的上限約爲40個項目)。所以我需要將Web客戶端請求分成40組,並決定使用隊列來完成。

下面是代碼:

public void some_method() 
     int num = 40; // readonly variable declared at top but put here for clarity 
     String hash = ""; 
     Queue<Action> temp_actions = new Queue<Action>(); 
     foreach (ItemViewModel item in collection) 
     { 
      num--; 
      hash += "&hash=" + item.Hash; // Add &hash + hash to hash 

      if (num == 0) 
      { 
       // Change status for these 40 items 
       temp_actions.Enqueue(() => auth.change_status_multiple(status, hash)); 

       // Reset variables 
       num = 40; 
       hash = ""; 
      } 
     } 

     // Enqueue the last action for the rest of the items 
     // Since "num == 0" doesn't cater for leftovers 
     // ie. 50 items and 40 in first set, 10 left (which will be enqueued here) 
     temp_actions.Enqueue(() => auth.change_status_multiple(status, hash)); 


     // Start the change status process 
     temp_actions.Dequeue().Invoke(); 

     actions = temp_actions; 
    } 

    public Queue<Action> actions { get; set; } 

    // Event handler for when change_status_multiple fires its event for finish 
    private void authentication_MultipleStatusChanged(object sender, EventArgs e) 
    { 
     if (actions.Count > 0) // Check if there are actions to dequeue 
      actions.Dequeue().Invoke(); 
    } 

但是,當涉及到運行時,哈希將是 「」。 例如,我有50個項目,40個將在第一個動作入隊,然後在第二個10個,但第一個集合的哈希字符串是「」。這是爲什麼?我一直認爲在將行爲排入隊列時,它會保留當時我提供的變量的任何值。

我調試了我的代碼,並在排隊第一個集合時,散列是正確的,但是當它重置變量num和hash時,第一個集合(在隊列中)的散列更改爲「」。

反正有這個嗎?

謝謝。

+0

我敢肯定,這是在C#中的「固定」 5.0 –

+0

也許吧,但我編程的Windows Phone 8(不當然,如果這是C#5.0?) – Travv92

+0

@ ta.speot.is:我的理解是,這種改變有效地將'foreach'循環中的循環變量的聲明移到了循環中。這個特殊的例子不會受到這個改變的影響,因爲它是* not *'item'被關閉。 http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx – spender

回答

2

你延遲執行的受害者......你在下一行捕捉hash範圍在委託:

temp_actions.Enqueue(() => auth.change_status_multiple(status, hash)); 
//... 
hash = ""; //happens before delegate above has executed 

然後立即清除hash爲「」。

委託運行時,hash已被清除。

要修復,利用hash

var hashCopy = hash; 
temp_actions.Enqueue(() => auth.change_status_multiple(status, hashCopy)); 
//... 
hash = ""; 
+0

謝謝,就是這樣! – Travv92

1

本地副本,這是因爲你的lambda表達式創建closure和捕捉statushash變量。

快速的解決方案是創建另一個變量,該變量將被代替捕獲:

string capturedHash = hash; 
temp_actions.Enqueue(() => auth.change_status_multiple(status, capturedHash)); 
+0

也謝謝。內容豐富的答案。 – Travv92