2010-12-02 94 views
1

我無法解釋我遇到的問題。基本上,如果我在foreach循環中使用lambda語法,而不是在for循環中使用它,則會得到不同的答案。在下面的代碼中,我在「調度員」類中註冊一個委託。然後,我在另一個委託的出路上包裝委託並返回這些委託的列表。然後我執行它們。執行包裝函數列表的預期輸出是1,2。然而,當我將lambda和foreach循環結合起來時,我沒有看到。使用for循環和帶閉包的foreach循環的不同行爲

這不是造成問題的代碼,而是我可以做出的最簡單的情況來重現它。我不想討論這個用例,我更好奇爲什麼我得到我不期待的行爲。如果我用下面的lambda語法使用foreach循環,它會失敗。如果我使用新的Action()語法和一個適用於其的foreach,如果我在for循環中使用lambda語法,它將起作用。任何人都可以解釋這裏發生了什麼。這讓我真的很難過。

public class Holder 
{ 
    public Holder(int ID, Dispatcher disp) 
    { 
     this.ID = ID; 
     disp.Register(Something); 
    } 
    public int ID { get; set; } 
    private void Something(int test) { Console.WriteLine(ID.ToString()); } 
} 

public class Dispatcher 
{ 
    List<Action<int>> m_Holder = new List<Action<int>>(); 

    public void Register(Action<int> func) 
    { 
     m_Holder.Add(func); 
    } 

    public List<Action<int>> ReturnWrappedList() 
    { 
     List<Action<int>> temp = new List<Action<int>>(); 

     //for (int i = 0; i < m_Holder.Count; i++)  //Works - gives 1, 2 
     //{ 
     // var action = m_Holder[i]; 
     // temp.Add(p => action(p)); 
     //} 

     foreach (var action in m_Holder) 
     { 
      temp.Add(p => action(p)); //Fails - gives 2,2 
      //temp.Add(new Action<int>(action)); Works - gives 1,2 
     } 

     return temp; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var disp = new Dispatcher(); 
     var hold1 = new Holder(1, disp); 
     var hold2 = new Holder(2, disp); 
     disp.ReturnWrappedList().ForEach(p => p(1)); 
    } 
} 

回答

0

你試過:

foreach (var action in m_Holder) 
{ 
    var a = action; 
    temp.Add(p => a(p)); 
} 
0

這是一個範圍,是不是你所期望的捕獲封閉的經典問題。在foreach中,該操作具有外部範圍,因此執行會捕獲該循環的最後一個值10。在這種情況下,您可以在內部作用域中創建操作,因此在每次迭代時閉包都會超過本地值。