373 votos

¿Abuso de C# expresiones lambda o brillantez de sintaxis?

Estoy mirando el MvcContrib Cuadrícula componente y estoy fascinado, pero al mismo tiempo rechazado, por un sintáctica truco en la Cuadrícula de la sintaxis:

.Attributes(style => "width:100%")

La sintaxis anterior establece el atributo de estilo de el código HTML generado width:100%. Ahora bien, si prestas atención, el " estilo " en ninguna parte se especifica, se deduce a partir del nombre del parámetro en la expresión! Tuve que cavar en esto y se encuentra en el lugar donde la " magia " que pasa:

   Hash(params Func<object, TValue>[] hash)
   {
     foreach (var func in hash)
     {
       Add(func.Method.GetParameters()[0].Name, func(null));
     }
   }

De hecho, el código es el uso de la formal, tiempo de compilación, el nombre de los parámetros para crear el diccionario de atributo de pares de nombre-valor. El resultado de la sintaxis de construcción es muy expresiva, pero al mismo tiempo muy peligroso. El uso general de las expresiones lambda permite el reemplazo de los nombres utilizados sin efectos secundarios. Puedo ver un ejemplo en un libro que dice que collection.ForEach(book => Fire.Burn(book)) sé que puedo escribir en mi código collection.ForEach(log => Fire.Burn(log)) y significa la misma cosa. Pero con el MvcContrib de la Cuadrícula de la sintaxis de aquí que, de repente, me encuentro el código que busca activamente y hace decisiones basadas en los nombres que yo elijo para mi variables!

Así que se trata de una práctica común con el de C# 3.5/4.0 la comunidad y de las expresiones lambda amantes? O es un pícaro uno de los trucos que maverick no debería preocuparse?

142voto

Marc Gravell Puntos 482669

Me parece que la extraño, no tanto por el nombre, sino porque el lambda es innecesario; podría usar un anónimo-tipo y ser más flexible:

.Attributes(new { style = "width:100%", @class="foo", blip=123 });

Este es un patrón que se usa en gran parte de ASP.NET MVC (por ejemplo), y tiene otros usos (una advertencia, nota también Ayende los pensamientos de si el nombre es una magia valor en lugar de la llamada)

131voto

Brian Puntos 82719

Esto tiene pobre interoperabilidad. Por ejemplo, considere este C# - F # ejemplo

C#:

public class Class1
{
    public static void Foo(Func<object, string> f)
    {
        Console.WriteLine(f.Method.GetParameters()[0].Name);
    }
}

F #:

Class1.Foo(fun yadda -> "hello")

Resultado:

se imprime "arg" (no "bla").

Como resultado, los diseñadores de la biblioteca deben o evitar este tipo de 'abusos', o bien proporcionar por lo menos una sobrecarga 'estándar' (por ejemplo que lleva el nombre de cadena como un parámetro adicional) si quieren tener buena interoperabilidad entre lenguajes. net.

128voto

Jeremy Skinner Puntos 721

Sólo quería lanzar en mi opinión (soy el autor de la MvcContrib cuadrícula componente).

Este es sin duda el lenguaje de abuso - sin duda. Sin embargo, yo no me considero verdaderamente es contra intuitivo - cuando usted mira una llamada a Attributes(style => "width:100%", @class => "foo")
Creo que es bastante obvio lo que está pasando (ciertamente no es peor que el anonimato tipo de enfoque). Desde un intellisense perspectiva, estoy de acuerdo en que es bastante opaco.

Para los interesados, un poco de información sobre su uso en MvcContrib...

He añadido esto a la red como una preferencia personal - no me gusta el uso del anonimato de los tipos de diccionarios (tener un parámetro que toma "objeto" es tan opaco como uno que toma de parámetros Func[]) y el Diccionario de inicializador de colección es bastante detallado (yo no soy también un fan de verbose interfaces fluidas, por ejemplo, tener que encadenar varias llamadas a un Atributo("estilo", "display:none")Atributo("clase", "foo"), etc.)

Si C# tenido menos detallado de sintaxis para el diccionario de literales, entonces yo no te hubiera molestado, incluyendo esta sintaxis en la cuadrícula componente :)

También quiero señalar que el uso de este en MvcContrib es completamente opcional - estos son los métodos de extensión que se envuelven las sobrecargas que tomar una IDictionary lugar. Creo que es importante que si usted proporciona un método como este también debe admitir una más 'normal', por ejemplo, para la interoperabilidad con otros lenguajes.

También, alguien mencionó la reflexión de sobrecarga', y yo sólo quería señalar que en realidad no hay mucho de una sobrecarga con esta estrategia - no hay ningún tiempo de ejecución de la reflexión o de la compilación de la expresión en cuestión (véase la http://blog.bittercoder.com/PermaLink,guid,206e64d1-29ae-4362-874b-83f5b103727f.aspx).

46voto

NotDan Puntos 9519

Yo prefiero

Attributes.Add(string name, string value);

Es mucho más explícito y estándar y nada es ser adquirida mediante el uso de Lambda.

44voto

Jason Punyon Puntos 21244

Bienvenido A Los Rieles De La Tierra :)

Realmente no hay nada de malo siempre y cuando usted sabe lo que está pasando. (Es cuando este tipo de cosas no está documentado bien que no es un problema).

La totalidad de los Rieles del marco está construido sobre la idea de convención sobre configuración. Nomenclatura de las cosas de cierta manera claves en un convenio que está utilizando y usted consigue un montón de funcionalidades de forma gratuita. Tras la convención de nomenclatura que se mete a donde vas más rápido. Todo funciona a la perfección.

Otro lugar donde he visto un truco como este es en la llamada al método de afirmaciones en Moq. Pasa un lambda, pero la lambda no se ejecuta nunca. Simplemente usa la expresión para asegurarse de que la llamada al método sucedido y lanzar una excepción si no.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by: