2012-09-13 25 views
0

從這個答案https://stackoverflow.com/a/6457528/299110與lambda表達式事件處理似乎有錯誤的參數值

我使用ctrl.PreRender += (sender, e) => ControlPreRender(ctrl, rule);到一個或多個控件foreach內,使用Ctrl和規則的每次更改值。

但是,當調用ControlPreRender方法時,rule參數看起來與事件處理程序附加到的發件人不符。

我知道我錯過了這裏的東西,不知道是什麼,但!

更新: 感謝您的答案,Eric Lippert的博客真的解釋了它。正如下選民的建議,我已經把更多的代碼如下,希望改善的問題了一下:

foreach (var ctrl in controls) 
{ 
    // ... 
    foreach (var rule in rules) 
    { 
     // ... 
     ctrl.PreRender += (sender, e) => ControlPreRender(ctrl, rule); 
    } 
} 

public static void ControlPreRender(Control ctrl, ControlRule rule) 
{ 
    // ... 
} 
+1

想法是...哪個?另外,你能展示更多的代碼嗎?否則,我們不可能知道您在匿名方法中使用的局部變量'ctrl'和'rule'會發生什麼。 –

+0

它可能與此有關:http://msdn.microsoft.com/en-us/library/ms173174(v=vs.80).aspx – BlackBear

+2

'rule'的作用域是什麼?聞起來像修改一個封閉的變量給我... – verdesmarald

回答

3

我想你想一個臨時變量:

foreach(var rule in rules) 
{ 
    var tmpRule = rule; 
    ctrl.PreRender += (sender, e) => ControlPreRender(sender as Control, tmpRule); 
} 

的原因是如下所示:如果沒有該臨時變量,則所有匿名方法都會引用相同的實例,當您遍歷所有規則時會發生變化。這被稱爲"access to modified closure"。正如erikkallen所提到的,這已在C#5中修復。

您可以輕鬆檢查自己:在規則參數中爲ControlPreRender和第一個斷點匹配make an object ID設置斷點。您將看到,在斷點的所有以下命中中,規則參數將具有相同的對象ID,這意味着它是完全相同的實例。

+1

備案:在C#5中進行了更改:http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx – erikkallen

+0

@erikkallen:謝謝你提醒我。 –

+1

根據OP甚至CTRL在循環內改變...除了引入另一個臨時的CTRL,ControlPreRender(ctrl,tmpRule)可以簡單地更改爲ControlPreRender(發件人,tmpRule) –

1

Eric Lippert對此發佈了two excellent blog posts。你會注意到,他們實際上對.NET 4.5做了一個突破性的改變,以使foreach循環像你所期望的那樣行爲。 (埃裏克指的是C#5,這容易混淆的是用於.NET 4.5的編譯器版本)埃裏克說,

「這是一個最常見的不正確的bug報告中,我們得到的。也就是說,有人認爲他們已經找到編譯器中的一個錯誤,但實際上編譯器是正確的。「

請注意@Daniel已經發布了正確的代碼,按照Eric的文章。

+0

這真的是一個C#的東西,而不是一個.NET事情。它已在C#5中修復,而不是在.NET 4.5中修復。因此,針對.NET 4的C#5仍然會修復該行爲,因爲它是導致此行爲的C#編譯器,而不是.NET運行時。 –

+0

感謝您的澄清。 – Olly