2009-11-12 93 views
12

我經常發現自己使用lambda表達式作爲某種「本地函數」使我的生活像的repetetive操作更加方便:什麼時候它太「lambda行動」?

Func<string, string> GetText = (resource) => this.resourceManager.GetString(resource); 
Func<float, object, string> FormatF1 = (f, o) => String.Format("{0:F1} {1}", f, o); 
Func<float, object, string> FormatF2 = (f, o) => String.Format("{0:F2} {1}", f, o); 

而不是一遍又一遍地寫的String.Format-的事情,我可以高興地用FormatF2吹走例如並節省了我自己的時間,當我需要改變某些格式時,只有一處進行編輯。 特別是當我只需要給定函數中的功能時,我很不情願將它們變成真正的函數。雖然上面的lambda表達式相對較小......有時我有一個較大的(以下應該將數據添加到一個表,打印輸出):

Action<string, string, string> AddSurfaceData = (resource, col, unit) => { 
    renderTable.Cells[tableRowIndex, 0].Text = "\t" + this.GetText(resource); 
    renderTable.Cells[tableRowIndex, 1].Text = FormatF2(paraHydReader.GetFloat(paraHydReader.GetOrdinal(col)), ""); 
    renderTable.Cells[tableRowIndex, 1].Style.TextAlignHorz = C1.C1Preview.AlignHorzEnum.Right; 
    renderTable.Cells[tableRowIndex, 2].Text = " " + this.GetText(unit); 
    renderTable.Cells[tableRowIndex, 2].Style.TextAlignHorz = C1.C1Preview.AlignHorzEnum.Left; 
    ++tableRowIndex; 
}; 

同樣,我需要這個經常和的所有優點以上也適用。然而,正如你所看到的,這個對lambda表達式來說是相當長的。問題是:你什麼時候畫線?我最後的lambda太多了嗎?還有什麼其他的方式(除了使用真正的函數或試圖在容器中填充數據並循環使用它們)存在以避免一次又一次地寫入相同的代碼?

在此先感謝

基督教

回答

11

這是你在一個方法中可能多次使用的東西,並且只能在該方法中使用。我喜歡這個想法。如果它不會讓你的代碼難以閱讀,那就去做吧。我想說,如果你很難看到lambda函數的內容與方法的實際內容是什麼,你應該重新考慮。在這種情況下,用單獨的私人方法把它拉出來可能會更清晰。

最後,這真是一個風格問題......

0

我個人認爲它不是好味道使用lambda函數時,有沒有必要爲它。我個人不會使用lambda函數來替換簡單的幾行程序代碼。 Lambda函數提供了許多增強功能,但使代碼稍微複雜一些。

我wouldnt用它來取代string.format。

+5

如果它是一個在同一個函數中多次使用的複雜'string.format',那麼使用它就非常合理。問題是,當函數變得如此複雜時,最好將它作爲一個單獨的私有方法在你的類中提取出來。 – awe 2009-11-12 08:38:50

2

我喜歡這個主意。我沒有看到更好的方式來保持代碼的本地化,而不違反DRY原則。如果你不習慣使用lambda表達式,那麼我認爲閱讀起來很難。

2

+1對nikie re DRY通常很好。

我不會爲他們使用PascalCase命名。

但要小心 - 在大多數情況下,您在那裏的東西只是一個穿着或潛在的助手或擴展功能的抽取方法。例如,GetText是一種方法,FormatF*可能是一種輔助方法...

6

我同意敬畏:對於方法(或甚至是類)內的小規模重用,這是完美的。像string.Format的例子。我經常使用它。這與使用局部變量對於多次使用的中間值(but then for code)基本相同。

你的第二個例子似乎在推動它。不知何故,這給了我一種私人方法AddSurfaceData(可能是靜態的,取決於它的用途?)的感覺會更合適。這當然不在您所處的背景之下,所以請使用您自己的良好判斷力。

+0

使方法成爲靜態或不依賴於用法 - 如果它使用成員變量,強制將參數傳遞給函數是沒有意義的。 – awe 2009-11-13 05:44:37

4

Lambda方法是一種匿名方法。

這意味着你不應該給它一個名字。

如果你這樣做了(就你而言,你正在爲你的引用指定一個名字),這只是另一種聲明函數的方法。

C#已經有了一種聲明函數的方式,它不是lambda方式,它唯一地加上了 來通過參數傳遞函數並返回它們作爲返回值。

想,作爲一個例子,在javascript:

function f(var1,var2,...,varX) 
{ 
    some code 
} 

var f = function() { 
    some code  
} 

不同的語法(幾乎)相同的事情。

有關爲什麼它不一樣的東西更多信息:Javascript: var functionName = function() {} vs function functionName() {}

又如:在Haskell你可以定義兩個函數:

function1 :: Int -> Int 
function1 x = x + 2 

function2 :: Int -> Int 
function2 = \x -> x + 2 

同樣的事情(這我認爲它是完全相同的),不同的語法。我更喜歡第一個,這更清楚。作爲Javascript,C#3.5已經獲得了許多功能性影響。其中一些應該明智地使用,恕我直言。

有人說在引用中帶有賦值的局部lambda函數可以很好地替代另一種方法中定義的方法,類似於Haskell中的「let」或「where」子句。

我說「相似」,因爲兩個有非常不同的語義,例如,在Haskell我可以使用尚未聲明的函數名稱,稍後用「where」定義它,而在C#中,使用函數/引用賦值我不能這樣做。順便說一句,我認爲這是一個好主意,我並不禁止使用lambda函數,我只是想讓人們考慮一下。每種語言都有他的抽象機制,明智地使用它。

+0

我知道Haskell,自從我學習它之後,我的C#編程已經變得更加「功能化」,所以我意識到我「有點」濫用了Lambdas作爲匿名函數的基本概念......但這樣做很誘人; ) 嘿,在C++中,我們濫用模板來計算斐波那契序列等:) – Christian 2009-11-12 09:19:12

+3

我認爲爲了尊重一般原則(lambda方法是匿名方法),不應禁止爲方法內的重複使用命名一個功能塊, 。 – 2009-11-12 09:21:56

+4

沒有什麼說lambda必須是「匿名的」......但是C#3缺乏聲明內部函數(這是一種恥辱)的能力;在上面的代碼中,雖然GetText,FormatF1和FormatF2可以展開到正確的[靜態]方法(儘管這可能會誤導他們的作用域!),但如果在最後一個示例中需要「閉包語義」,則沒有指定。 – 2009-11-12 09:25:51

2

我對長示例沒有任何問題。我發現你非常優雅地重新包裝複合數據。

這是短小的,將促使你的同事調查自願機構化的優勢。請聲明一些常量來保存你的格式字符串,並且使用「那個反覆的String.Format事物」。作爲一名C#程序員,我知道如果不在別處尋找自主創建的函數,它會做什麼。這樣,當我需要知道格式化字符串是什麼樣子時,我可以檢查常量。

1

我同意在一般volothamp,但除了...

認爲,要保持你的代碼的其他人。我覺得這是很容易,你的第一個例子就明白了,並仍然提供你所提到的維護方面的優勢:

String.Format(this.resourceManager.GetString("BasicFormat"), f, o); 
String.Format(this.resourceManager.GetString("AdvancedFormat"), f, o); 

而且你的第二個例子似乎只是來聲明函數以不同的方式。我沒有看到任何聲明輔助方法的好處。對大多數編碼人員來說,聲明一個輔助方法會更容易理解。

相關問題