2011-12-02 52 views
1

這是種一個奇怪的問題,但它想出了一天,它有我的思考。什麼時候lambda表達式中的參數首選?

當它是優選的設計以這種形式 「(X => x.Whatever)」 節 「(()=> obj.Whatever)」 使用lambda表達式。

考慮下面的擴展方法。

public static class ExtensionMethods 
{ 
    public static string TryToGetTheString<T>(this T value, Func<T, string> method) 
    { 
     try 
     { 
      return method(value); 
     } 
     catch (Exception) 
     { 
      return "banana"; 
     } 
    } 

    public static string TryToGetTheStringTwo<T>(this T value, Func<string> method) 
    { 
     try 
     { 
      return method(); 
     } 
     catch (Exception) 
     { 
      return "banana"; 
     } 
    } 
} 

和下面的自引用類。

public class testClass5000 
{ 
    private int? _id; 
    public int? ID { get { return _id; } set { _id = value; } } 

    private string _urgh; 
    public string Urgh { get; set; } 

    public testClass5000 tc5k { get; set; } 
} 

然後使用一個非常懶惰的過程中要避免檢查空值,在試圖獲得一個字符串從testClass5000(Urgh),可以實現擴展的方法和像這樣的類,

private void main() 
    { 
     var tc = new testClass5000(); 

     textBox1.text = tc.TryToGetTheString(x => x.tc5k.tc5k.tc5k.Urgh); 

    } 

然而,因爲tc是在本地聲明的,以下也適用。

private void main() 
    { 
     var tc = new testClass5000(); 

     textBox1.text = tc.TryToGetTheStringTwo(() => tc.tc5k.tc5k.tc5k.Urgh); 

    } 

我好奇當(x => x.tc5k.tc5k.tc5k.Urgh)是必要的,並且當(() => tc.tc5k.tc5k.tc5k.Urgh)是優選的。

//////////////////////////////////////////

我確實想到了傳遞參數似乎更可取的情況。

用下面的擴展方法。

public static class ExtensionMethods 
{ 
    public static T TestOne<T>(this T value, Func<T, T> method) 
    { 
     try 
     { 
      return method(value); 
     } 
     catch (Exception) 
     { 
      return default(T); 
     } 
    } 

    public static T TestTwo<T>(this T value, Func<T> method) 
    { 
     try 
     { 
      return method(); 
     } 
     catch (Exception) 
     { 
      return default(T); 
     } 
    } 
} 

並使用下面的代碼。

private void Form1_Load(object sender, EventArgs e) 
    { 
     var firstValue = 5; 
     var secondValue = 10; 

     var resultOne = firstValue.TestOne(x => x + 1).TestOne(x => x * 2); 
     //returns 12 
     var resultTwo = secondValue.TestTwo(() => secondValue + 1).TestTwo(() => secondValue * 2); 
     //returns 20 
     var resultThree = secondValue.TestTwo(() => secondValue.TestTwo(() => secondValue + 1) * 2); 
     //returns 22 
    } 

在這個例子中.TestOne(X => X + 1).TestOne(X => X * 2)是優選的,因爲符號,以實現同樣的事情不經過需要啓動嵌套表達式paremeter。

+0

不要抓'異常'!在所有這些情況下,我會選擇完全忽略try/catch,並讓調用代碼失敗,然後以默認返回值隱藏問題。 – asawyer

+0

是的,我同意,這只是一個快速入侵,創造出現問題的場景。 – moctopus

回答

3

在其中的參數根本不一樣的,你所提供的原始值的情況。

粗例子

public static class Extensions 
{ 
    public static void DoSomething(this string s,Action<string> action) 
    { 
     var something = Enumerable.Range(1,100).Select(i=> String.Format("{0}_{1}",s,i)); 
     foreach (var ss in something) 
     { 
      action(ss); 
     } 
    } 
} 

然後

var something = "ABC123"; 

something.DoSomething(x=>Console.WriteLine(x)); 
//Ignoring that we could do something.DoSomething(Console.WriteLine); 

顯然沒有參數,你不能訪問你insterested實際值,原值爲這個概念中沒有用的。

4

直接在拉姆達注入參數值是更昂貴,因爲編譯器必須創建一個特殊的班級只是爲了這個目的。如果我們排除性能方面的考慮,那麼我會說注入參數更容易編寫(這裏是個人偏好),並且保持參數在原型中((x,y)=> //做某事)是有用的當你實際上不是提供參數值的人。例如,使用Select Linq查詢時。或者我經常使用它來實現負載平衡場景(一個lambda「service => service.SomeFunction()」,然後一個特殊的工廠檢索服務並執行lambda)。

+0

+1:「當你實際上不是提供參數值的那個人」是關鍵所在。 – GazTheDestroyer

+0

'x =>'版本不捕獲任何變量,因此可以重新使用單個靜態lambda。 '()=>'版本需要變量捕獲,這意味着每次調用時都會創建一個新的lambda,並且每次訪問'tc時都會調用一個額外的間接級別,因爲編譯器需要確保if你的lambda做'tc = newValue',這個新值對封閉函數是可見的。進一步討論[這裏](http://blogs.msdn.com/b/oldnewthing/archive/2006/08/02/686456.aspx)。 –

+0

哦,很酷。謝謝,我要讀這個。 – moctopus