C # Pass Lambda Expression como parámetro de método


105

Tengo una expresión lambda que me gustaría poder transmitir y reutilizar. Aquí está el código:

public List<IJob> getJobs(/* i want to pass the lambda expr in here */) {
  using (SqlConnection connection = new SqlConnection(getConnectionString())) {
    connection.Open();
    return connection.Query<FullTimeJob, Student, FullTimeJob>(sql, 
      (job, student) => {         
        job.Student = student;
        job.StudentId = student.Id;
        return job;
        },
        splitOn: "user_id",
        param: parameters).ToList<IJob>();   
  }   

La clave aquí es que quiero poder pasar la expresión lambda que estoy usando aquí al método que llama a este código, para poder reutilizarlo. La expresión lambda es el segundo argumento dentro de mi método .Query. Supongo que querría usar una acción o una función, pero no estoy muy seguro de cuál es la sintaxis para esto o cómo funciona. ¿Alguien puede darme un ejemplo?


3
Haga del parámetro una Acción o una Func.
— Metro Smurf

Bien, eso es lo que pensé ... ¿puedes mostrarme un ejemplo de cómo haría esto?
— Adam Levitt

posible duplicado de expresiones lambda
— usuario

Respuestas:


122

Utilice un Func<T1, T2, TResult>delegado como tipo de parámetro y páselo a su Query:

public List<IJob> getJobs(Func<FullTimeJob, Student, FullTimeJob> lambda)
{
  using (SqlConnection connection = new SqlConnection(getConnectionString())) {
    connection.Open();
    return connection.Query<FullTimeJob, Student, FullTimeJob>(sql, 
        lambda,
        splitOn: "user_id",
        param: parameters).ToList<IJob>();   
  }  
}

Lo llamarías:

getJobs((job, student) => {         
        job.Student = student;
        job.StudentId = student.Id;
        return job;
        });

O asignar el lambda a una variable y pasar a lo en.


Esto se ve muy bien, y ¿cómo definiría la lambda FUERA de este método getJobs? En otras palabras, ¿cuál es la línea antes de la llamada a getJobs () para definir el lambda?
— Adam Levitt

@AdamLevitt: de la misma manera que lo ha hecho con su código de ejemplo. Agregará para responder.
— Oded el

Además, ¿los parámetros de la función pueden ser dinámicos de alguna manera?
— Adam Levitt

@AdamLevitt: puede hacer que la función sea genérica, aunque si desea diferentes números de parámetros en las lambdas, necesitará sobrecargas.
— Oded el

Correcto. Lo que realmente me gustaría es poder pasar diferentes implementaciones de la interfaz IJob, pero eso no funcionará con Dapper's Query <> porque requiere la clase impl genérica real en tiempo de ejecución. Esto todavía está bastante cerca de lo que esperaba.
— Adam Levitt

27

Si entiendo, necesita el siguiente código. (pasando expresión lambda por parámetro) El método

public static void Method(Expression<Func<int, bool>> predicate) { 
    int[] number={1,2,3,4,5,6,7,8,9,10};
    var newList = from x in number
                  .Where(predicate.Compile()) //here compile your clausuly
                  select x;
                newList.ToList();//return a new list
    }

Método de llamada

Method(v => v.Equals(1));

Puedes hacer lo mismo en su clase, mira este ejemplo.

public string Name {get;set;}

public static List<Class> GetList(Expression<Func<Class, bool>> predicate)
    {
        List<Class> c = new List<Class>();
        c.Add(new Class("name1"));
        c.Add(new Class("name2"));

        var f = from g in c.
                Where (predicate.Compile())
                select g;
        f.ToList();

       return f;
    }

Método de llamada

Class.GetList(c=>c.Name=="yourname");

Espero que esto sea útil


2
¿Puede explicarnos por qué necesitamos Compile()el .Where? También he visto que funciona sin eso.
— Sнаđошƒаӽ

7

Las expresiones lambda tienen un tipo de Action<parameters>(en caso de que no devuelvan un valor) o Func<parameters,return>(en caso de que tengan un valor de retorno). En su caso, tiene dos parámetros de entrada y necesita devolver un valor, por lo que debe usar:

Func<FullTimeJob, Student, FullTimeJob>

5

Debe usar un tipo de delegado y especificarlo como parámetro de comando. Puede usar uno de los tipos de delegado integrados, Actiony Func.

En su caso, parece que su delegado toma dos parámetros y devuelve un resultado, por lo que podría usar Func:

List<IJob> GetJobs(Func<FullTimeJob, Student, FullTimeJob> projection)

Entonces podrías llamar a tu GetJobs método pasando una instancia delegada. Este podría ser un método que coincida con esa firma, un delegado anónimo o una expresión lambda.

PD: Debería utilizar PascalCase para los nombres de métodos GetJobs, no getJobs.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.