2016-09-27 18 views
2

我找到了帶有lambda表達式的參數的啓動線程解決方案。lambda是如何工作的? c#和線程

Thread amazonBuy1 = new Thread(() => amazon.Buy("Lego", visa, dhl)); 

所以,我的問題是 - lambda的工作原理是什麼? 當說到線程參數時,如何給出一個帶有參數的方法,它不可能作爲默認值。

謝謝。

+1

@ marc-gravell的答案的簡短版本是它創建了所謂的「閉包」,以便lambda方法運行時可以訪問'amazon','visa'和'dhl'變量。網上有很多很好的資源可以解釋如何使用閉包,而Marc的答案提供瞭如何在C#中實現它們的細節,如果您有興趣。 –

回答

2

如果我們把您的來電:

Thread amazonBuy1 = new Thread(() => amazon.Buy("Lego", visa, dhl)); 

...它重構爲兩條獨立的線路,我們得到這樣的:

ThreadStart threadStart =() => amazon.Buy("Lego", visa, dhl); 
Thread amazonBuy1 = new Thread(threadStart); 

所以構造函數Thread不走"Lego"visa,dhl參數 - 它只需要一個ThreadStart委託。

委託是一個可用於調用方法的變量。在這種情況下,委託人在調用時可以運行amazon.Buy("Lego", visa, dhl)

這意味着線程可以啓動,然後從新線程內部調用代理

編譯器會執行所有的神奇的功能,允許visadhl捆綁在代理內部。這被稱爲「封閉」。編譯器生成一個代理,該代理關閉兩個變量的

0

lambda表達式是一個匿名函數,它主要用於在LINQ中創建委託。簡而言之,它是一種沒有聲明的方法,即訪問修飾符,返回值聲明和名稱。方便。這是一種速記,允許您在要使用它的相同位置編寫一個方法。

來源:https://msdn.microsoft.com/en-GB/library/bb397687.aspx

Thread需要一個叫做ThreadStartParameterizedThreadStart委託。所以當你像這樣使用lambda時,你正在創建委託方法。

+0

已編輯。是的,它呢?他問什麼lambda是什麼,它做了什麼。這正是它告訴他的。 – ThePerplexedOne

+0

你的答案是不完整的,因爲它沒有描述爲lambda創建閉包的事實。 –

4

請允許我以證明編譯器有什麼:

class __horribleTypeName { 
    public Something amazon; 
    public SomethingElse visa; 
    public AnotherSomething dhl; 
    public void __horribleMethodName() { 
     amazon.Buy("Lego", visa, dhl); 
    } 
} 

... 

var __horribleLocalName = new __horribleTypeName(); 
__horribleLocalName.amazon = ... // etc 
Thread amazonBuy1 = new Thread(__horribleLocalName.__horribleMethodName); 

有意義嗎?所以lambda的內容成爲編譯器生成方法的方法體。您在本體內部訪問的本地文件被解壓到編譯器生成的實例中的字段。請注意,這裏使用的實際名稱都是「不可計數的」 - 它們不能用C#表示 - 它們不是合法的C#標識符(但是合法的IL標識符)。上面是一個簡單的例子 - 編譯器在某些情況下還可以進行其他優化,包括將事情提升到重用的靜態委託實例(當沒有捕獲上下文時)。還請注意,如果visadlhamazon實例字段,那麼您捕獲的是this,而不是字段本身;所以它可能是:

class __horribleTypeName { 
    public YourType __this; 
    public void __horribleMethodName() { 
     __this.amazon.Buy("Lego", __this.visa, __this.dhl); 
    } 
} 
... 
var __horribleLocalName = new __horribleTypeName(); 
__horribleLocalName.__this = this; 
Thread amazonBuy1 = new Thread(__horribleLocalName.__horribleMethodName); 

作爲一個方面說明:如果你想在狀態傳遞給一個線程,有一個ParameterizedThreadStart

+0

從這個描述中我不清楚的是局部變量在啓動線程的方法中被解除。否則,我們只會引用稍後修改方法的陳舊副本。 – Voo

+0

@Voo確實;要使用第一個例子,並不是說* amazon的值*在線程啓動之前就被解除了; **在原始方法中,所有提到**的「amazon」實際上都是在與'__horribleLocalName.amazon'交談; *變量本身*被重新定位 –

+0

事實上,我只是想強調這一點,因爲我覺得這可能會丟失,因爲它是在當前的答案。 – Voo