2009-11-12 13 views
12

Spesso mi capita utilizzando lambda come una sorta di "funzioni locali" per rendere la vita più facile con le operazioni ripetitiva come quelli:Quando è troppo "azione 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); 

invece di scrivere lo String.Format-cosa più e più, posso felicemente soffiare via con FormatF2 es e risparmiare tempo e quando ho bisogno di cambiare qualcosa sulla formattazione, solo un posto per fare modifiche. Specialmente quando ho bisogno esclusivamente della funzionalità nella funzione data, sono molto riluttante a trasformarli in una funzione reale. Mentre il lambda sopra erano relativamente piccola ... a volte devo quelli più grandi come (si suppone quanto segue per aggiungere dati a una tabella per l'output di stampa):

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

Anche in questo caso, ho bisogno di questo, spesso e tutti i vantaggi di sopra si applicano anche. Tuttavia, come puoi vedere, questo è piuttosto lungo per un'espressione lambda. La domanda è: quando disegni la linea? Il mio ultimo lambda è troppo? In quali altri modi (a parte l'utilizzo di funzioni reali o il tentativo di riempire i dati in contenitori e di ricollegarli) per evitare di scrivere lo stesso codice più e più volte?

Grazie in anticipo

Christian

risposta

11

È qualcosa che usi potenzialmente molte volte in un metodo, e solo all'interno di quel metodo. Mi piace questa idea. Fallo se non rende il tuo codice difficile da leggere. Direi che dovresti riconsiderare se trovi difficile vedere qual è il contenuto della funzione lambda rispetto a quale sia il vero contenuto del metodo. In tal caso potrebbe essere più pulito estrarlo in un metodo privato separato.

Alla fine, questo è davvero una questione di gusto ...

0

io personalmente pensa che la sua non è di buon gusto per utilizzare le funzioni lambda quando non v'è alcun bisogno di esso. Personalmente non userò una funzione lambda per sostituire poche semplici righe di codice procedurale. Le funzioni Lambda offrono molti miglioramenti, ma rendono il codice leggermente più complicato da leggere.

Non lo userei per sostituire string.format.

+5

Se è un 'string.format' complesso che viene usato molte volte nella stessa funzione, ha perfettamente senso usarlo. La domanda è davvero quando la funzione diventa così complicata che è meglio estrarla come metodo privato separato nella tua classe. – awe

2

Mi piace l'idea. Non vedo un modo migliore per mantenere la località del codice senza violare il principio DRY. E penso che sia più difficile da leggere se non sei abituato a lambda.

2

+1 su nikie re ASCIUTO essere buoni in generale.

Tuttavia, non utilizzerei il nome PascalCase per loro.

Attenzione però: nella maggior parte dei casi, il materiale in dotazione è solo un metodo di estrazione in un vestito o una potenziale funzione di supporto o di estensione. ad esempio, GetText è un metodo e probabilmente è un metodo di supporto ...

6

Sono d'accordo con soggezione: per il riutilizzo su piccola scala all'interno di un metodo (o anche di una classe) questo è perfetto. Come gli esempi string.Format. Lo uso abbastanza spesso. È praticamente la stessa cosa di utilizzare una variabile locale per un valore intermedio che si utilizza più di una volta, but then for code.

Il tuo secondo esempio sembra spingerlo un po '. In qualche modo questo mi dà la sensazione che un metodo privato AddSurfaceData (probabilmente statico, a seconda del suo utilizzo?) Sarebbe una soluzione migliore. Ovviamente, al di fuori del contesto che hai, usa il tuo buon giudizio.

+0

Rendere il metodo statico o meno dipende dall'uso - Se utilizza le variabili membro, non è necessario forzare il passaggio come parametri alla funzione. – awe

4

Un metodo Lambda è un metodo anonimo.

Ciò significa che non si deve dare un nome.

Se lo fai, (nel tuo caso, stai assegnando un nome con il tuo riferimento), è solo un altro modo per dichiarare una funzione.

C# ha già un modo per dichiarare le funzioni, e non è il modo lambda, che è stato aggiunto in modo univoco per passare funzioni tramite parametri e li restituisce come valori di ritorno.

Pensate, ad esempio, in javascript:

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

o

var f = function() { 
    some code  
} 

Differente sintassi (quasi) stessa cosa.

Per ulteriori informazioni sul motivo per cui non è la stessa cosa: Javascript: var functionName = function() {} vs function functionName() {}

Un altro esempio: in Haskell È possibile definire due funzioni:

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

o

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

stessa cosa (questo tempo penso che sia lo stesso), diversa sintassi. Preferisco il primo, è più chiaro.

C# 3.5, come Javascript, ha un sacco di influenze funzionali. Alcuni di loro dovrebbero essere usati saggiamente, IMHO.

Qualcuno ha detto che le funzioni lambda locali con assegnazione in un riferimento sono un buon sostituto di un metodo definito all'interno di un altro metodo, simile a una clausola "let" o "where" in Haskell.

Dico "simile" perché i due hanno semantica molto diversa, ad esempio in Haskell posso usare il nome funzione che non è stato ancora dichiarato e definirlo in seguito con "dove", mentre in C#, con funzione/assegnazione di riferimento Non posso farlo

A proposito, penso che sia una buona idea, non sto bandendo questo uso della funzione lambda, voglio solo far riflettere la gente su questo. Ogni lingua ha il suo meccanismo di astrazione, usalo saggiamente.

+0

Conosco Haskell e da quando l'ho imparato, la mia programmazione in C# è diventata più "funzionale", quindi sono consapevole di "abusare" un po 'dell'idea di base di Lambdas come funzioni anonime ... ma è molto allettante farlo;) E ciao, in C++ abusiamo di modelli per calcolare sequenze di fibonacci ecc. – Christian

+3

Penso che nominare un blocco funzionale per uso ripetuto all'interno di un metodo non dovrebbe essere vietato per il rispetto di un principio generale (i metodi lambda sono metodi anonimi) . –

+4

Non c'è nulla che dice che un lambda deve essere "anonimo" ... Tuttavia C# 3 non ha la capacità di dichiarare le funzioni interiori (che è una vergogna); nel codice sopra, mentre GetText, FormatF1 e FormatF2 potrebbero essere srotolati ai metodi [statici] corretti (anche se potrebbe essere fuorviante sul loro ambito!) non è specificato se nell'ultimo esempio è necessaria una "semantica di chiusura". –

2

Non ho alcun problema con il lungo esempio. Vedo che stai riconfezionando i dati composti in modo molto elegante.

Sono i corti che guideranno i colleghi a indagare sui vantaggi dell'istituzionalizzazione volontaria. Si prega di dichiarare un qualche tipo di costante per contenere la stringa di formato e utilizzare "quella stringa.Formato-cosa più e più volte". Come programmatore C#, so cosa succede senza cercare altrove le funzioni di home-spun. In questo modo, quando ho bisogno di sapere come sarà la stringa formattata, posso semplicemente esaminare la costante.

1

Sono d'accordo con volothamp in generale, ma in aggiunta ...

Pensate alle altre persone che hanno per mantenere il vostro codice.Credo che questo sia facile da capire che il vostro primo esempio e offre ancora i benefici di manutenzione di cui parli:

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

E il tuo secondo esempio sembra essere solo un modo diverso per dichiarare una funzione. Non vedo alcun utile vantaggio rispetto alla dichiarazione di un metodo di supporto. E dichiarare un metodo di supporto sarà più comprensibile per la maggior parte dei programmatori.