2011-07-31 23 views
26

一般來說,我得到了C#的lambda語法。然而,匿名線程語法並不完全清楚。有人可以解釋像這樣的線程創建實際上在做什麼?請儘可能詳細,我希望有一個一步一步的魔術,使這項工作。C#使用Lambda語法的匿名線程

(new Thread(() => { 
     DoLongRunningWork(); 
     MessageBox.Show("Long Running Work Finished!"); 
    })).Start(); 

,我真的不明白的部分是Thread(() => ...

當我使用這個語法好像我刪除了很多的限制的傳統,如需要調用一個方法ThreadStart沒有參數。

感謝您的幫助!

+0

它創建一個新的線程對象傳入一個匿名方法(委託),並啓動它。就這樣。創建匿名方法本質上是一種將代碼塊作爲委託參數傳遞的方法 –

回答

34

() => ...只是表示lambda表達式不帶任何參數。你舉的例子是等同於以下:

void worker() 
{ 
    DoLongRunningWork(); 
    MessageBox.Show("Long Running Work Finished!"); 
} 

// ... 

new Thread(worker).Start(); 

在lambda的{ ... }讓你用在lambda體內,在那裏通常你只被允許表達多個語句。

此:

() => 1 + 2 

等同於:

() => { return (1 + 2); } 
+0

這部分讓我感覺到,但我也可以這樣做:'new Thread(()=> _Transaction_Finalize_Worker(transId,machine,info,newConfigPath ))。Start();' - 爲什麼我現在可以傳入所有這些參數? – jocull

+3

因爲lambda表達式可以從其外部範圍捕獲變量。看看關閉:http://en.wikipedia.org/wiki/Closure_(computer_science) –

+1

closures,yo:http://en.wikipedia.org/wiki/Closure_%28computer_science%29 – anthony

10

由於有一些答案我開始之前,我就只寫有關如何額外的參數使其進入拉姆達。

總之這個東西叫做關閉。讓我們把你的例子與new Thread(() => _Transaction_Finalize_Worker(transId, machine, info, newConfigPath)).Start();分解。

對於關閉,類的字段和局部變量之間存在差異。因此我們假設transId是class字段(因此可通過this.transId訪問),其他字段僅爲局部變量。

如果在類編譯器中使用lambda創建嵌套類並帶有難以名稱的名稱,則在幕後,爲簡單起見,將其命名爲X,並將所有局部變量放在那裏。它也寫lambda,所以它成爲正常的方法。然後編譯器重寫您的方法,以便它在某個時刻創建X,並分別用x.machine,x.infox.newConfigPath替換對machineinfonewConfigPath的訪問。另外X收到對this的引用,所以lambda-method可以通過parentRef.transId訪問transId

那麼,它是非常簡化,但接近現實。


UPD:

class A 
{ 
    private int b; 

    private int Call(int m, int n) 
    { 
     return m + n; 
    } 

    private void Method() 
    { 
     int a = 5; 
     a += 5; 
     Func<int> lambda =() => Call(a, b); 
     Console.WriteLine(lambda()); 
    } 

    #region compiler rewrites Method to RewrittenMethod and adds nested class X 
    private class X 
    { 
     private readonly A _parentRef; 
     public int a; 

     public X(A parentRef) 
     { 
      _parentRef = parentRef; 
     } 

     public int Lambda() 
     { 
      return _parentRef.Call(a, _parentRef.b); 
     } 
    } 

    private void RewrittenMethod() 
    { 
     X x = new X(this); 
     x.a += 5; 
     Console.WriteLine(x.Lambda()); 
    } 
    #endregion 
} 
+2

謝謝,我想我明白現在發生了什麼 - 很多匿名類型的魔法! – jocull

4

這是建立在C#中的線程剛剛啓動線程匿名的方式(),因爲你正在使用開始(;) 以下2種辦法是等價的。如果你需要Thread變量來做某事(例如通過調用thread0.join()來阻塞調用線程),那麼你使用第二個。

new Thread(() => 
{ 
    Console.WriteLine("Anonymous Thread job goes here..."); 
}).Start(); 

var thread0= new Thread(() => 
{ 
    Console.WriteLine("Named Thread job goes here..."); 
}); 
thread0.Start(); 

現在是Thread方法的一部分。如果你看到線程聲明,我們有以下(我省略了另外3個)。

public Thread(ThreadStart start); 

線程將委託作爲參數。委託是參考一種方法。所以Thread需要一個參數,它是一個委託。 ThreadStart是這樣聲明的。

public delegate void ThreadStart(); 

這意味着你可以將任何方法傳遞給Thread,它返回void並且不接受任何參數。所以下面的例子是等價的。

ThreadStart del = new ThreadStart(ThreadMethod); 
var thread3 = new Thread(del); 
thread3.Start(); 

ThreadStart del2 = ThreadMethod; 
var thread4 = new Thread(del2); 
thread4.Start(); 

var thread5 = new Thread(ThreadMethod); 
thread5.Start(); 

//This must be separate method 
public static void ThreadMethod() 
{ 
    Console.WriteLine("ThreadMethod doing important job..."); 
} 

現在我們認爲ThreadMethod方法做的工作量很小,我們可以把它做到本地和匿名。所以我們根本不需要ThreadMethod方法。

new Thread(delegate() 
    { 
     Console.WriteLine("Anonymous method Thread job goes here..."); 
    }).Start(); 

您在委託給最後一個花括號後看到的等價於我們的ThreadMethod()。您可以通過引入Lambda語句進一步縮短以前的代碼(請參閱MSDN)。這只是你正在使用,看看它是如何結束如下。

new Thread(() => 
{ 
    Console.WriteLine("Lambda statements for thread goes here..."); 
}).Start();