2014-03-27 97 views
3

爲什麼下面的語法有效?Lambda with BackgroundWorker

BackgroundWorker bw = new BackgroundWorker(); 
String one = resultFromSomeMethod(); 
String two = resultFromOtherMethod(); 
String three = resultFromThirdMethod(); 
bw.DoWork += (a,b) => TestMethod(one, two, three); 

其中TestMethod的定義爲:

private void TestMethod(String one, String two, String three){ 
    //Do Stuff!! 
} 

DoWorkEventHandler的被定義爲代表的是有兩個參數:對象發件人和EventArgs的。但是,上面的TestMethod不包含這樣的參數。根據我對委託人的理解,爲了創建一個新委託,該方法必須符合委託人的聲明。我似乎已經繞過了使用lambda的限制。如何以及爲什麼上面的語法工作,即使如果我嘗試創建一個new DoWorkEventHandler(TestMethod)它肯定不會工作?

我在Lambda表達式上閱讀了Eric White的blog,但似乎沒有回答這個問題。

回答

10

讓我澄清一下拉姆達對你:

(a,b) => TestMethod("", "", ""); 

翻譯爲:

private void AnonymousLambda(object a, EventArgs b) 
{ 
    TestMethod("", "", ""); 
} 

拉姆達的語法是:

implicit method arguments => method body 

隱式方法參數由該方法分配給(或從中調用)的預期簽名決定。由於您將此lambda表達式分配給DoWorkEventHandler委託人,因此它會自動將ab分別解釋爲objectEventArgs

在某些情況下,編譯器不能推斷隱含類型的拉姆達的參數,所以你也可以有明確寫入其中:

(object a, EventArgs b) => TestMethod("", "", ""); 

所以,你真的叫你TestMethod的在體內另一種你匿名創建的方法!外部方法有DoWorkEventHandler方法簽名。

編輯

每對字符串變量的附加問題的細節,編譯器在你的代碼中創建一個封閉以包括方法的範圍的變量。該代碼基本上變成持有的變量爲私有領域一個新的類,然後調用它們的引用:

public class AnonymousClosureClass 
{ 
    public void AnonymousLambda(object a, EventArgs b) 
    { 
     // Note the reference to the original class instance 
     String one = originalClassReference.one; 
     String two = originalClassReference.two; 
     String three = originalClassReference.three; 
     TestMethod(one, two, three); 
    } 
} 

而且主代碼實際上變成:

BackgroundWorker bw = new BackgroundWorker(); 

// Note: these may become field members to remain visible to the closure class 
String one = resultFromSomeMethod(); 
String two = resultFromOtherMethod(); 
String three = resultFromThirdMethod(); 

var closure = new AnonymousClosureClass(); 
bw.DoWork += closure.AnonymousLambda; 

最後,值得一提的,這是而不是實際生成的閉包代碼是如何命名或外觀的。

+0

我明白,但TestMethod參數不在範圍內。 – KyleM

+3

您將'TestMethod'參數封裝在與委託簽名匹配的函數中,因此它可以工作。這也被稱爲適配器模式,儘管它是一個簡單的例子。 – Haney

+0

@Servy感謝您對這個缺失逗號的追蹤! – Haney

5

TestMethod正在從(a,b)函數調用。它

這樣看,而不是:

BackgroundWorker bw = new BackgroundWorker(); 
bw.DoWork += DoWorkFunc; 

void DoWorkFunc(object a, EventArgs b) 
{ 
    TestMethod("", "", ""); 
} 
5

參數在您的代碼的(a,b)部分中定義。這些對應於object senderDoWorkEventArgs e。也就是說,你的拉姆達類似於下面的代碼:

BackgroundWorker bw = new BackgroundWorker(); 
bw.DoWork += new DoWorkEventHandler(MyFunction); 


void MyFunction(object a, DoWorkEventArgs b) 
{ 
    TestMethod("", "", ""); 
} 

,你不使用的參數,或返回的TestMethod的價值其實是無關緊要的。

(比作Func<int, int>myFunc = c => c + 1拉姆達當量)

int MyFunction(int c) 
{ 
    return c + 1; 
} 
5

委託的論點根本未使用。 Lambda是以下方法的等價物:

void LambdaMethod(object a, DoWorkEventArgs b) 
{ 
    TestMethod("", "", ""); 
}