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?

Adam Levitt
fuente
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.

Oded
fuente
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

Marinpietri
fuente
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>
SztupY
fuente
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.

devdigital
fuente