2016-08-10 86 views
0

我在努力弄清代表和lambda表達式,並通過一些問題在這裏讀取了stackoverflow並降落在此post第二個示例in this comment讓我完全丟失。第一件讓我困惑的事情是list參數沒有在任何地方定義(我明白它是返回類型的輸入參數,但我覺得很難理解這段代碼),但我認爲通過了解這樣的定義可以在實踐中使用(這是我難以掌握的第二件事)。返回委託的方法

如何在實踐中使用以下方法?

public Func<IList<T>, T> SelectionMethod<T>() 
{ 
    return list => list.First(); 
} 

public Func<float, float> QuadraticFunctionMaker(float a , float b , float c) 
{ 
    return (x) => { return a * x * x + b * x + c; }; 
} 

回答

1

參數被定義,只是它們的類型被推斷出來。參數定義是=> - list(推斷爲IList<T>類型)和x(推斷爲float類型)之前的部分,分別在您的示例中。

首先代表對應的簽名:

T SomeMethod<T>(IList<T> list) 

二是:

float SomeMethod(float x) 

由於編譯器知道委託的簽名必須是什麼,它可以推斷出所需要的類型自動。如果你是使用舊的學校明確語法寫出來的代表,它會是這個樣子:

return (Func<IList<T>, T>)(delegate (IList<T> list) { return list.First(); }); 

如果你真的想使用顯式類型,您可以指定類型的需要:

(IList<T> list) => list.First() 

當你真正要調用的委託,你需要傳遞參數,如:

SelectionMethod<string>()(new List<string>()) 

第一個lambda表達式是非常簡單的。第二種方法還關閉了「creator」函數的參數,這意味着您可以訪問委託主體中「creator」的參數。這在純粹不可變的代碼中是完全安全的,但是如果你處理可變引用類型和副作用可能會很棘手 - 確保你在對這些引用做任何事情之前正確理解語義。

根據您在函數式編程方面的經驗,瞭解所有這些只是編譯器的詭計可能會有幫助。這兩種方法將編譯到的東西相當於這樣的:

public Func<IList<T>, T> SelectionMethod<T>() 
{ 
    return new Func<IList<T>, T>(__HiddenAnonymousMethod); 
} 

private T __HiddenAnonymousMethod<T>(IList<T> list) 
{ 
    return list.First(); 
} 

第二個例子是比較複雜的,因爲封閉的 - 我們需要創建一個「輔助對象」來保存捕獲當地人:

private class __HiddenAnonymousClass 
{ 
    float a, b, c; 

    public __HiddenAnonymousClass(float a, float b, float c) 
    { 
    this.a = a; this.b = b; this.c = c; 
    } 

    public float __HiddenAnonymousMethod(float x) 
    { 
    return a * x * x + b * x + c; 
    } 
} 

public Func<float, float> QuadraticFunctionMaker(float a , float b , float c) 
{ 
    return new Func<float, float> 
    (new __HiddenAnonymousClass(a, b, c).__HiddenAnonymousMethod); 
} 
+0

很好的解釋。我確實發現所有這些新的語法越來越模糊,我傾向於避免在我的代碼中使用任何語法快捷方式,我覺得它們使代碼更不易讀。 – Stefano