2009-09-16 9 views
14

¿Es posible tener un interruptor en una expresión lambda? Si no, ¿por qué? Resharper lo muestra como un error.C# interruptor en la expresión lambda

+7

¿Compila? No usaría Resharper como palabra final sobre la sintaxis válida. –

+0

Claro que no y el error compilado es el mismo que el resultado mostrado por el reafilado: una expresión lambda con una instrucción boody no se puede convertir a un árbol de expresiones. – Toto

+0

NB: No sé lo que es un cuerpo de declaración. – Toto

Respuesta

21

Puede lambda en un bloque de instrucciones:

Action<int> action = x => 
{ 
    switch(x) 
    { 
    case 0: Console.WriteLine("0"); break; 
    default: Console.WriteLine("Not 0"); break; 
    } 
}; 

Pero no se puede hacer en una "expresión lambda única", por lo que este no es válida:

// This won't work 
Expression<Func<int, int>> action = x => 
    switch(x) 
    { 
    case 0: return 0; 
    default: return x + 1; 
    }; 

Esto significa que puede No uso el modificador en un árbol de expresiones (al menos como lo genera el compilador de C#; creo que .NET 4.0 al menos tiene soporte para él en las bibliotecas).

+0

sí parece que el problema es que quiero un árbol de expresiones. ¿Hay algún trabajo mejor que un if si un functino? – Toto

+0

Una pequeña corrección (en retrospectiva ... ¿cuánto es bueno en retrospectiva :-)). El compilador de C# 4.0 aún no puede construir 'expresiones' complejas (con 'if',' while' ...) pero puedes construirlas mediante el uso de la clase 'Expression'. Las dos cosas están desacopladas.Y con menos retrospectiva: el OP preguntó acerca de los árboles de expresión. La segunda 'acción' debería haber sido una' Expresión > 'para mostrar que realmente quería un Árbol de Expresión y no un delegado. – xanatos

+0

@xanatos: Gracias, he editado. –

2

Hmm, no veo ninguna razón por la que esto no debería funcionar. Solo tenga cuidado con la sintaxis que usa

param => { 
    // Nearly any code! 
} 

delegate (param) { 
    // Nearly any code! 
} 

param => JustASingleExpression (No switches) 
5

Sí, funciona, pero debe poner su código en un bloque. Ejemplo:

private bool DoSomething(Func<string, bool> callback) 
{ 
    return callback("FOO"); 
} 

Luego, para lo llaman:

DoSomething(val => 
       { 
        switch (val) 
        { 
         case "Foo": 
          return true; 

         default: 
          return false; 
        } 
       }); 
2

he comprobado también :-)

[Test] 
public void SwitchInLambda() 
{ 
    TakeALambda(i => { 
     switch (i) 
     { 
      case 2: 
       return "Smurf"; 
      default: 
       return "Gnurf"; 
     } 
    }); 
} 

public void TakeALambda(Func<int, string> func) 
{ 
    System.Diagnostics.Debug.WriteLine(func(2)); 
} 

funciona bien (salidas "Pitufo")!

+2

Porque eso no es una expresión de Lambda. A ** Lambda Expression ** sería del tipo 'Expression >'. Esa es una ** Función Lambda **. Intente cambiar el parámetro de entrada de TakeALambda y vea la diferencia. – xanatos

11

En una pura Expression (en .NET 3.5), el más cercano que puedes conseguir es un compuesto condicional:

Expression<Func<int, string>> func = x => 
     x == 1 ? "abc" : (
     x == 2 ? "def" : (
     x == 3 ? "ghi" : 
       "jkl")); /// yes, this is ugly as sin... 

No es divertido, especialmente cuando se pone compleja. Si se refiere a una expresión lambda con un cuerpo de la declaración (sólo para uso con LINQ a Objetos), entonces cualquier cosa es legal dentro de las llaves:

Func<int, string> func = x => { 
     switch (x){ 
      case 1: return "abc"; 
      case 2: return "def"; 
      case 3: return "ghi"; 
      default: return "jkl"; 
     } 
    }; 

Por supuesto, es posible que pueda subcontratar el trabajo; por ejemplo, LINQ a SQL permite asignar una UDF escalar (en la base de datos) a un método en el contexto de datos (que no se utiliza en realidad) - por ejemplo:

var qry = from cust in ctx.Customers 
      select new {cust.Name, CustomerType = ctx.MapType(cust.TypeFlag) }; 

donde es MapType un UDF que hace el trabajo en el servidor de db.

+1

Puede omitir los paréntesis en su primer código; el resultado es * mucho * menos feo y en realidad lo uso a veces. Es cierto que lleva un tiempo acostumbrarse, pero no es intrínsecamente menos legible que un bloque de 'interruptor' equivalente (menos, diría yo). –

+0

Sin los soportes a veces me pierdo? /: etc ... pero sí, puede funcionar sin ellos ;-p –

+0

@MarcGravell ¿Todavía no hay nada mejor para una 'Expresión' pura en .Net 4.0? – ken2k