2012-10-27 20 views
0

可能重複:
C# - The foreach identifier and closures
From Eric Lippert’s blog: 「don’t close over the loop variable」Lambda表達式爲的ThreadStart奇怪的行爲

我使用Lambda表達式作爲ThreadStart參數,使用運行在一個新線程的方法Thread班。這是我的代碼:

delegate void del(); 

static void Do(int i) 
{ 
    Console.WriteLine(i); 
} 

static del CreateLoop(del Do) 
{ 
    return() => 
    { 
     while (true) 
     { 
      Do(); 
      Thread.Sleep(500); 
     } 
    }; 
} 

static void Main(string[] args) 
{ 
    int n = 0; 
    var loop = CreateLoop(() => Do(n)); 
    new Thread(() => loop()).Start(); 
    Thread.Sleep(500); 
    n = 1; 
} 

這是輸出:

0 
1 
1 
1 
... 

這怎麼可能?
爲什麼如果我更改我的整數變量n的值,還會更改iDo的參數)的值?

+0

@ L.B是關於變量範圍,而不是關於捕獲的變量... – gliderkite

+1

gliderkite,所以你遇到一個非常特殊的情況,沒有人面臨過?再次閱讀參考。 –

回答

0

您應該製作一個不同的變量,因此不會更改原始值。

畢竟,你真正要做的就是調用同樣的舊'函數',lambda表達式一遍又一遍地傳遞變量i,這確實會改變。這就像你在某處存儲var的初始值一樣。

0
var loop = CreateLoop(() => Do(n)); 

此行只是建立一個新的功能,並將其分配給一個變量。除其他功能外,此功能將值n傳遞給Do函數。但它不是調用Do函數,它只是創建一個函數,在執行時調用Do函數。

然後開始一個調用函數等的新線程,但是您的新線程仍在執行Do(n),將n變量傳遞給Do。該部分不會改變 - 您創建了一個函數,該函數引用內存中的特定位置(由變量n表示),並繼續將該位置引用到內存中,即使在您更改存儲在那裏的值時也是如此。

我相信下面就「修理」你的代碼:

var loop = (int x) =>() => CreateLoop(() => Do(x)); 
new Thread(loop(n)).Start(); 

這傳遞的nloop表示的函數值,但loop功能在內存中創建一個新的地方(由x表示)在其中存儲該值。內存中的這個新位置不會受到對n的後續更改的影響。也就是說,你創建的函數並不直接引用內存中的地址,而n是一個指針。