2009-11-12 17 views
12

I często znajduję się przy użyciu lambdy jako pewnego rodzaju „lokalnych” funkcji, aby moje życie łatwiejszym z repetetive operacji, takich jak te:Kiedy jest za dużo "akcji 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); 

zamiast pisania string.Format-rzeczy w kółko, mogę szczęśliwie zdmuchnąć za pomocą FormatF2 np i zaoszczędzić czas i kiedy muszę zmienić coś na temat formatowania, tylko jedno miejsce do wprowadzania zmian. Szczególnie, gdy potrzebuję funkcji wyłącznie w danej funkcji, bardzo niechętnie zmieniam ją w prawdziwą funkcję. Choć lambdas powyżej były stosunkowo małe ... czasami mam większych tacy jak (Następujące ma dodać dane do tabeli dla wydruków):

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; 
}; 

Znowu muszę to często i wszystkie korzyści płynące z powyżej również obowiązują. Jednak, jak widać, ten jest dość długi na wyrażenie lambda. Pytanie brzmi: Kiedy narysujesz linię? Czy moja ostatnia lambda jest zbyt duża? Jakie inne sposoby (poza używaniem rzeczywistych funkcji lub próbowaniem wypychania danych w kontenerach i pętlą nad nimi) istnieją, aby uniknąć pisania tego samego kodu w kółko?

góry dzięki

Christian

Odpowiedz

11

Jest to coś, czego używasz potencjalnie wiele razy w ramach metody, i tylko to, że wewnątrz tej metody. Podoba mi się ten pomysł. Zrób to, jeśli nie utrudnia odczytania kodu. Powiedziałbym, że powinieneś ponownie rozważyć, czy trudno ci zobaczyć, jaka jest zawartość funkcji lambda, a jaka jest prawdziwa treść tej metody. W takim przypadku może być czystsze wyciągnięcie go w oddzielnej, prywatnej metodzie.

Na koniec, to jest naprawdę kwestia gustu ...

0

ja osobiście myślę że jest nie w dobrym smaku, aby wykorzystać funkcje lambda gdy nie ma takiej potrzeby. Osobiście nie użyję funkcji lambda do zastąpienia kilku prostych linii kodu proceduralnego. Funkcje Lambda oferują wiele ulepszeń, ale sprawiają, że kod jest nieco bardziej skomplikowany do czytania.

Nie użyłbym go do zamiany string.format.

+5

Jeśli jest złożonym 'string.format', który jest używany wiele razy w tej samej funkcji, ma to sens z jego używania. Pytanie brzmi, kiedy funkcja staje się tak skomplikowana, że ​​lepiej jest ją wyciągnąć jako oddzielną prywatną metodę w swojej klasie. – awe

2

podoba mi się pomysł. Nie widzę lepszego sposobu na utrzymanie lokalizacji kodu bez naruszenia zasady DRY. I myślę, że trudniej jest przeczytać, jeśli nie jesteś przyzwyczajony do lambd.

2

+1 na nikie re DRY jest ogólnie dobry.

Nie używałbym jednak nazw PascalCase.

Bądź jednak ostrożny - w większości przypadków rzeczy, które tam masz, są tylko metodą wyodrębniania w sukience lub potencjalnym pomocnikiem lub funkcją rozszerzenia. np. GetText jest metodą, a FormatF* jest prawdopodobnie metodą pomocniczą ...

6

Zgadzam się z podziwem: do ponownego użycia w małej skali wewnątrz metody (lub nawet klasy) jest to idealne. Podobnie jak w przypadku przykładów string.Format. Używam tego dość często. Jest to zasadniczo to samo, co użycie zmiennej lokalnej dla wartości pośredniej, której używasz więcej niż jeden raz, but then for code.

Twój drugi przykład wydaje się nieco naciskać. W jakiś sposób daje mi to poczucie, że prywatna metoda byłaby lepiej dopasowana (w zależności od jej użycia?). Jest to oczywiście poza kontekstem, który masz, więc wykorzystaj swoją własną, zdrową ocenę.

+0

Dokonywanie metody statycznej lub nie zależy od użycia - jeśli używa zmiennych składowych, nie ma sensu zmuszanie do przekazywania parametrów do funkcji. – awe

4

Metoda Lambda jest metodą anonimową.

Oznacza to, że nie należy podawać nazwy.

Jeśli to robisz, (w twoim przypadku przypisujesz nazwę z referencją), jest to po prostu inny sposób deklarowania funkcji.

C# ma już sposób deklarowania funkcji, a nie jest to metoda lambda, która została dodana jako , aby przekazywać funkcje za pośrednictwem parametrów i zwracać je jako wartości zwracane.

sądzę, jako przykład, w javascript:

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

lub

var f = function() { 
    some code  
} 

innej składni (prawie) to samo.

Aby uzyskać więcej informacji na temat, dlaczego to nie jest to samo: Javascript: var functionName = function() {} vs function functionName() {}

Inny przykład: w Haskell Można zdefiniować dwie funkcje:

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

lub

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

samo (ten czas myślę, że to jest to samo), inna składnia. Wolę ten pierwszy, jest bardziej przejrzysty.

C# 3.5, jako Javascript, ma wiele wpływów funkcjonalnych. Niektóre z nich powinny być mądrze wykorzystane, IMHO.

Ktoś powiedział, że lokalne funkcje lambda z przypisaniem w referencji są dobrym substytutem metody zdefiniowanej w innej metodzie, podobnie do klauzuli "let" lub "where" w Haskell.

Mówię "podobny", ponieważ dwójki mają bardzo różną semantykę, na przykład w Haskell mogę używać nazwy funkcji, która nie jest jeszcze zadeklarowana i zdefiniować ją później jako "gdzie", natomiast w języku C#, z przypisaniem funkcji/odwołania Nie mogę tego zrobić.

Przy okazji, wydaje mi się, że to dobry pomysł, nie zakazuję używania funkcji lambda, chcę tylko skłonić ludzi do myślenia o tym. Każdy język ma swój mechanizm abstrakcji, używaj go mądrze.

+0

Znam Haskella i odkąd się go nauczyłem, moje programowanie w języku C# stało się bardziej "funkcjonalne", więc zdaję sobie sprawę, że "nieco" nadużywałem podstawowej idei Lambdas jako anonimowych funkcji, ale jest to bardzo kuszące;) I hej, w C++ używamy szablonów do obliczania sekwencji fibonacci itp :) – Christian

+3

Myślę, że nazywanie bloku funkcjonalnego do wielokrotnego użytku wewnątrz metody nie powinno być zakazane ze względu na poszanowanie ogólnej zasady (metody lambda są metodami anonimowymi) . –

+4

Nic nie mówi, że lambda musi być "anonimowa" ... Jednak C# 3 nie ma możliwości zadeklarowania wewnętrznych funkcji (co jest wstydem); w powyższym kodzie, podczas gdy GetText, FormatF1 i FormatF2 mogły zostać rozwinięte do odpowiednich metod [statycznych] (chociaż może to wprowadzać w błąd ich zakres!), nie jest to określone, jeśli w ostatnim przykładzie wymagana jest "semantyka zamknięcia". –

2

Nie mam problemu z długim przykładem. Widzę, że przepakowujesz złożone dane bardzo elegancko.

Te krótkie sprawiają, że twoi koledzy badają zalety dobrowolnej instytucjonalizacji. Proszę zadeklarować jakąś stałą, aby utrzymać ciąg znaków w formacie i używać "tego String.Format-rzeczy w kółko". Jako programista C#, wiem, co to robi, nie szukając gdzie indziej funkcji domowych. W ten sposób, gdy będę musiał wiedzieć, jak będzie wyglądał sformatowany ciąg, mogę po prostu sprawdzić stałą.

1

zgadzam się z volothamp w ogóle, ale oprócz ...

myśleć o innych osób, które muszą utrzymać swój kod.Myślę, że jest to łatwiejsze do zrozumienia niż pierwszego przykładu i nadal oferuje korzyści konserwacji można wymienić:

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

A twój drugi przykład wydaje się być po prostu inny sposób deklarowania funkcji. Nie widzę żadnej użytecznej korzyści w stosunku do deklarowania metody pomocniczej. Oświadczenie metody pomocniczej będzie bardziej zrozumiałe dla większości programistów.