2009-11-12 9 views
12

a menudo me encuentro usando lambdas como una especie de "funciones" locales para hacer la vida más fácil con las operaciones repetitivos como los que:¿Cuándo es demasiado "acción 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); 

lugar de escribir el String.Format-cosa una y otra vez, con mucho gusto puede volar con FormatF2, por ejemplo y ahorrarme tiempo y cuando necesito cambiar algo sobre el formato, solo un lugar para hacer ediciones. Especialmente cuando necesito la funcionalidad en la función dada exclusivamente, soy muy reacio a convertirlos en una función real. Mientras que el lambdas anteriormente eran relativamente pequeña ... a veces tengo más grandes como (se supone lo siguiente para agregar datos a una tabla para la salida de impresión):

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

Una vez más, necesito esto a menudo y todos los beneficios de la arriba aplicar, también. Sin embargo, como pueden ver, esta es bastante larga para una expresión lambda ... la pregunta es: ¿cuándo trazas la línea? ¿Mi última lambda es demasiado? ¿Qué otras formas (aparte de usar funciones reales o intentar rellenar los datos en contenedores y recorrerlos) existen para evitar escribir el mismo código una y otra vez?

Gracias de antemano

Cristiano

Respuesta

11

Es algo que utiliza potencialmente muchas veces dentro de un método, y solo eso dentro de ese método. Me gusta esta idea. Hazlo si no hace que tu código sea difícil de leer. Diría que debería reconsiderar si le resulta difícil ver cuál es el contenido de la función lambda frente a cuál es el contenido real del método. En ese caso, podría ser más limpio extraerlo en un método privado separado.

Al final, esto es realmente una cuestión de gusto ...

0

personalmente creo que no es de buen gusto para utilizar las funciones lambda cuando no hay necesidad de hacerlo. Personalmente no usaré una función lambda para reemplazar unas pocas líneas de código de procedimiento. Las funciones de Lambda ofrecen muchas mejoras, pero hacen que el código sea un poco más complicado de leer.

No lo usaría para reemplazar string.format.

+5

Si se trata de un '' string.format' complejo que se usa muchas veces en la misma función, tiene mucho sentido usarlo. La pregunta es realmente cuando la función se vuelve tan complicada que es mejor sacarla como un método privado separado en su clase. – awe

2

me gusta la idea. No veo una mejor manera de mantener la localidad del código sin violar el principio DRY. Y creo que es más difícil de leer si no estás acostumbrado a lambdas.

2

+1 en nikie re DRY siendo bueno en general.

Sin embargo, no utilizaría la denominación PascalCase para ellos.

Sin embargo, tenga cuidado: en la mayoría de los casos, lo que tiene allí es solo un Método de Extracción en un vestido o un ayudante potencial o función de extensión. por ejemplo, GetText es un método y FormatF* es probablemente un método de ayuda ...

6

Estoy de acuerdo con la reverencia: para la reutilización a pequeña escala dentro de un método (o incluso una clase) esto es perfecto. Como los ejemplos string.Format. Yo uso esto con bastante frecuencia. Básicamente es lo mismo que usar una variable local para un valor intermedio que usa más de una vez, but then for code.

Su segundo ejemplo parece estar presionándolo un poco. De alguna manera, esto me da la sensación de que un método privado AddSurfaceData (posiblemente estático, dependiendo de su uso?) Sería una mejor opción. Eso es, por supuesto, fuera del contexto que tiene, así que use su propio buen juicio.

+0

Hacer que el método sea estático o no depende del uso: si usa variables miembro, no tiene sentido obligar a pasar como parámetros a la función. – awe

4

Un método Lambda es un método anónimo.

Esto significa que no debe darle un nombre.

Si está haciendo eso, (en su caso, está asignando un nombre con su referencia), es simplemente otra forma de declarar una función.

C# ya tiene una forma de declarar funciones, y no es la forma lambda, que se agregó de forma única para pasar funciones a través de parámetros y los devuelve como valores de retorno.

pensar, como un ejemplo, en javascript:

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

o

var f = function() { 
    some code  
} 

sintaxis diferente (casi) lo mismo.

Para obtener más información acerca de por qué no es la misma cosa: Javascript: var functionName = function() {} vs function functionName() {}

Otro ejemplo: en Haskell Se pueden definir dos funciones:

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

o

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

lo mismo (esto tiempo, creo que es lo mismo), sintaxis diferente. Prefiero el primero, es más claro.

C# 3.5, como Javascript, tiene muchas influencias funcionales. Algunos de ellos deben ser utilizados sabiamente, en mi humilde opinión.

Alguien dijo que las funciones lambda locales con asignación en una referencia son un buen sustituto para un método definido en otro método, similar a una cláusula "let" o "where" en Haskell.

Digo "similar" porque los dos tienen una semántica muy diferente, por ejemplo, en Haskell puedo usar nombre de función que todavía no está declarado y definirlo más tarde con "where", mientras estoy en C#, con asignación de función/referencia No puedo hacer esto

Por cierto, creo que es una buena idea, no estoy prohibiendo este uso de la función lambda, solo quiero que la gente piense al respecto. Cada idioma tiene su mecanismo de abstracción, úselo sabiamente.

+0

Conozco a Haskell y desde que lo aprendí, mi programación en C# se ha vuelto más "funcional", así que soy consciente de que "de alguna manera" abuso de la idea básica de Lambdas siendo funciones anónimas ... pero es muy tentador hacerlo;) Y bueno, en C++ abusamos de las plantillas para calcular las secuencias de fibonacci, etc. :) – Christian

+3

Creo que nombrar un bloque funcional para un uso repetido dentro de un método no debe prohibirse por el respeto de un principio general (los métodos lambda son métodos anónimos) . –

+4

No hay nada que diga que una lambda debe ser "anónima" ... Sin embargo, C# 3 carece de la capacidad de declarar funciones internas (lo cual es una pena); en el código anterior, mientras que GetText, FormatF1 y FormatF2 podrían desenrollarse a métodos apropiados [estáticos] (¡aunque eso podría inducir a error sobre su alcance!) no se especifica si se necesita una "semántica de cierre" en el último ejemplo. –

2

No tengo ningún problema con el largo ejemplo. Veo que está reempacando datos compuestos muy elegantemente.

Son los breves los que motivarán a sus colegas a investigar las ventajas de la institucionalización voluntaria. Por favor, declare algún tipo de constante para mantener su cadena de formato y use "ese String.Format-thing una y otra vez". Como programador de C#, sé lo que hace sin buscar en otra parte las funciones de inicio hilado. De esa forma, cuando necesite saber cómo se verá la cadena formateada, puedo examinar la constante.

1

Estoy de acuerdo con volothamp en general, pero además ...

pienso en las otras personas que tienen que mantener su código.Creo que esto es más fácil de entender que el primer ejemplo y todavía ofrece los beneficios de mantenimiento que mencionas:

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

Y el segundo ejemplo parece ser sólo una manera diferente a declarar una función. No veo ningún beneficio útil sobre declarar un método de ayuda. Y declarar un método de ayuda será más comprensible para la mayoría de los codificadores.

Cuestiones relacionadas