C#中循環(huán)中的捕獲變量我遇到了一個關(guān)于C#的有趣問題。我有如下代碼。List<Func<int>> actions = new List<Func<int>>();int variable = 0;while (variable < 5){
actions.Add(() => variable * 2);
++ variable;}foreach (var act in actions){
Console.WriteLine(act.Invoke());}我希望它輸出0,2,4,6,8。但是,它實際輸出5個10。似乎是由于所有操作都涉及一個捕獲的變量。結(jié)果,當(dāng)它們被調(diào)用時,它們都具有相同的輸出。有沒有辦法解決這個限制,讓每個動作實例都有自己的捕獲變量?
4 回答

呼啦一陣風(fēng)
TA貢獻1802條經(jīng)驗 獲得超6個贊
是 - 在循環(huán)中獲取變量的副本:
while (variable < 5){ int copy = variable; actions.Add(() => copy * 2); ++ variable;}
您可以將其視為C#編譯器每次命中變量聲明時都創(chuàng)建一個“新”局部變量。實際上它會創(chuàng)建適當(dāng)?shù)男麻]包對象,如果你在多個范圍內(nèi)引用變量,它會變得復(fù)雜(在實現(xiàn)方面),但是它可以工作:)
請注意,此問題更常見的是使用for
或foreach
:
for (int i=0; i < 10; i++) // Just one variable foreach (string x in foo) // And again, despite how it reads out loud
有關(guān)詳細信息,請參閱C#3.0規(guī)范的第7.14.4.2節(jié),關(guān)于閉包的文章也有更多示例。

慕婉清6462132
TA貢獻1804條經(jīng)驗 獲得超2個贊
在幕后,編譯器生成一個表示方法調(diào)用閉包的類。它為循環(huán)的每次迭代使用閉包類的單個實例。代碼看起來像這樣,這使得更容易看到錯誤發(fā)生的原因:
void Main(){ List<Func<int>> actions = new List<Func<int>>(); int variable = 0; var closure = new CompilerGeneratedClosure(); Func<int> anonymousMethodAction = null; while (closure.variable < 5) { if(anonymousMethodAction == null) anonymousMethodAction = new Func<int>(closure.YourAnonymousMethod); //we're re-adding the same function actions.Add(anonymousMethodAction); ++closure.variable; } foreach (var act in actions) { Console.WriteLine(act.Invoke()); }}class CompilerGeneratedClosure{ public int variable; public int YourAnonymousMethod() { return this.variable * 2; }}
這實際上不是您的示例中的已編譯代碼,但我已經(jīng)檢查了自己的代碼,這看起來非常類似于編譯器實際生成的內(nèi)容。
- 4 回答
- 0 關(guān)注
- 675 瀏覽
添加回答
舉報
0/150
提交
取消