C # Pass Lambda Expression as Method Parameter

106

Eu tenho uma expressão lambda que gostaria de poder transmitir e reutilizar. Aqui está o 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>();   
  }   

A chave aqui é que eu quero ser capaz de passar a expressão lambda que estou usando aqui para o método que está chamando este código, para que eu possa reutilizá-la. A expressão lambda é o segundo argumento dentro do meu método .Query. Estou supondo que gostaria de usar uma ação ou função, mas não tenho certeza de qual é a sintaxe para isso ou como funciona. Alguém pode me dar um exemplo?

Adam Levitt
fonte
3
Torne o parâmetro uma ação ou uma função.
Metro Smurf
Certo, foi o que pensei ... você pode me mostrar um exemplo de como eu faria isso?
Adam Levitt
possível duplicata de expressões C # lambda como argumentos de função
usuário

Respostas:

123

Use um Func<T1, T2, TResult>delegado como o tipo de parâmetro e passe-o para o seu 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>();   
  }  
}

Você o chamaria de:

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

Ou atribua o lambda a uma variável e passe -o .

Oded
fonte
Isso parece muito bom, e como eu definiria o lambda FORA deste método getJobs? Em outras palavras, como é a linha antes da chamada para getJobs () para definir o lambda?
Adam Levitt de
@AdamLevitt - Da mesma forma que você fez com seu código de exemplo. Adicionará para responder.
Oded
Além disso, os parâmetros da função podem ser dinâmicos de alguma forma?
Adam Levitt
@AdamLevitt - você pode tornar a função genérica, embora se quiser números diferentes de parâmetros nos lambdas, você precisará de sobrecargas.
Oded
Certo. O que eu realmente gostaria é ser capaz de passar em diferentes implementações da interface IJob, mas isso não funcionará com Dapper's Query <> porque requer a classe impl genérica real em tempo de execução. Isso ainda está muito perto do que eu esperava.
Adam Levitt
27

Se eu entender, você precisa seguir o código. (passando a expressão lambda por parâmetro) O 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 chamada

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

Você pode fazer o mesmo em sua classe, veja este é um exemplo.

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 chamada

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

Espero que seja útil

Marinpietri
fonte
2
Você pode explicar por que precisamos Compile()do .Where? Eu vi que funciona sem isso também.
Sнаđошƒаӽ
7

As expressões lambda têm um tipo de Action<parameters>(caso não retornem um valor) ou Func<parameters,return>(caso tenham um valor de retorno). No seu caso, você tem dois parâmetros de entrada e precisa retornar um valor, então você deve usar:

Func<FullTimeJob, Student, FullTimeJob>
SztupY
fonte
5

Você deve usar um tipo de delegado e especificá-lo como seu parâmetro de comando. Você pode usar um dos tipos integrados de delegado - ActioneFunc .

No seu caso, parece que seu delegado usa dois parâmetros e retorna um resultado, então você pode usar Func:

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

Você pode então chamar seu GetJobsmétodo passando em uma instância delegada. Pode ser um método que corresponda a essa assinatura, um delegado anônimo ou uma expressão lambda.

PS Você deve usar PascalCase para nomes de métodos - GetJobs, não getJobs.

devdigital
fonte