2014-03-31 75 views
1

我一直在看這段代碼。我意識到,爲什麼這總會拋出不支持的觀點,因爲溫度總是等於20;然而,我希望有人向我解釋爲什麼temp總是等於20,而不是在循環中設置爲temp的值。有人可以向我解釋爲什麼這不起作用嗎?

{ 
    delegate int Del(int i); 
    static event Del MyEvent; 

    static void Main(string[] args) 
    { 
     for (int i = 0; i < 20; i++) 
      MyEvent += a => 
      { 
       int temp = i; 
       if (a != temp) throw new NotSupportedException(); 
       return a * 2; 

      }; 

     Console.WriteLine("C'est fini"); 
     Console.WriteLine(GetValue(5)); 

     Console.ReadLine(); 
    } 

    static int GetValue(int arg) 
    { 
     foreach(Del myEvent in MyEvent.GetInvocationList()) 
     { 
      try 
      { 
       return myEvent(arg); 
      } 
      catch(NotSupportedException) 
      { 
       continue; 
      } 
     } 
     throw new NotSupportedException(); 
    } 
} 
+0

這是因爲封鎖和它已經回答得非常好這裏http://stackoverflow.com/questions/5438307/detailed-explanation-of-variable-capture-in-closures – BenCr

+0

是因爲總是不等於我所以它是拋出異常,而不是它的返回聲明? – Ronnie

+0

@BenCr謝謝!我不知道它叫什麼,我爲重複道歉。我正在閱讀你鏈接的問題。 – Aelphaeis

回答

4

i是在封閉使用。你有這樣的循環:

for (int i = 0; i < 20; i++) 
     MyEvent += a => 
      { 
       int temp = i; 
       if (a != temp) throw new NotSupportedException(); 
       return a * 2; 
      }; 

拉姆達使用i,我不值。換句話說,您在這裏創建的代表實際上是指由循環正在更改的變量i 。解決此問題的簡單方法是使用一個局部變量來強制關閉捕捉到一個沒有被修改的變量:

for (int i = 0; i < 20; i++) 
    { 
     var value = i; 
     MyEvent += a => 
      { 
       int temp = value; 
       if (a != temp) throw new NotSupportedException(); 
       return a * 2; 
      }; 
    } 

乍一看,你可能會認爲這不解決您的問題。但本地變量value實際上是每個迭代的不同變量。當該變量在閉包中被捕獲時,它將不會被循環更新。

6

在你的處理程序定義你關閉了循環變量i,不是i電流值,所以當你在所有的註冊的處理程序達到循環結束,i = 20。您可以通過複製i到另一個循環變量解決這個問題:

for (int i = 0; i < 20; i++) 
{ 
    int temp = i; 
    MyEvent += a => 
    { 
     if (a != temp) throw new NotSupportedException(); 
     return a * 2; 
    }; 
} 
+0

有沒有一種方法可以在委託人訂閱該事件時使用我的值來更改此行爲? – Aelphaeis

+0

@Aelphaeis - 是的,複製循環內的當前值。查看更新。 – Lee

1
for (int i = 0; i < 20; i++) 
     MyEvent += a => 
     { 
      int temp = i; 
      if (a != temp) throw new NotSupportedException(); 
      return a * 2; 

     }; 

我想有人向我解釋爲什麼溫度總是等於20,而不是這是設置爲臨時在循環值。

的事情是,temp沒有被設置爲環路什麼。你在做什麼是聲明一個新的匿名方法(使用args => {}語法或lambda表達式)。

您的MyEvent委託人然後彙總指向您所有20個新匿名方法的指針。

這些20種方法將不會被執行,直到觸發事件,其中發生在這條線:

return myEvent(arg); 

到那個時候,i是20所以temp也將是20

2

只需將temp移動到閉包外。

for (int i = 0; i < 20; i++) 
{ 
    int temp = i; 
    MyEvent += a => 
    { 
     if (a != temp) throw new NotSupportedException(); 
     return a * 2; 
    }; 
} 
相關問題