C # Przekaż wyrażenie lambda jako parametr metody

106

Mam wyrażenie lambda, które chciałbym móc przekazać i ponownie wykorzystać. Oto kod:

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>();   
  }   

Kluczem tutaj jest to, że chcę móc przekazać wyrażenie lambda, którego używam tutaj, do metody, która wywołuje ten kod, aby móc go ponownie użyć. Wyrażenie lambda jest drugim argumentem wewnątrz mojej metody .Query. Zakładam, że chciałbym użyć Action lub Func, ale nie jestem do końca pewien, jaka jest składnia tego lub jak to działa. Czy ktoś może mi podać przykład?

Adam Levitt
źródło
3
Ustaw parametr jako Action lub Func.
Metro Smurf
Tak właśnie myślałem ... czy możesz mi pokazać przykład, jak bym to zrobił?
Adam Levitt,
możliwy duplikat wyrażeń lambda C # jako argumentów funkcji
użytkownik

Odpowiedzi:

123

Użyj Func<T1, T2, TResult>delegata jako typu parametru i przekaż go do 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>();   
  }  
}

Nazwałbyś to:

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

Lub przypisz lambdę do zmiennej i przekaż .

Oded
źródło
Wygląda to bardzo dobrze i jak zdefiniowałbym lambdę OUTSIDE tej metody getJobs? Innymi słowy, jak wygląda linia przed wywołaniem metody getJobs () w celu zdefiniowania lambdy?
Adam Levitt,
@AdamLevitt - tak samo jak w przypadku przykładowego kodu. Dodam do odpowiedzi.
Oded
Czy w ogóle parametry funkcji mogą być dynamiczne?
Adam Levitt,
@AdamLevitt - możesz sprawić, że funkcja będzie generyczna, ale jeśli chcesz mieć różne liczby parametrów na lambdach, będziesz potrzebować przeciążeń.
Oded
Dobrze. Właściwie chciałbym móc przekazywać różne implementacje interfejsu IJob, ale to nie zadziała z Query <> Dappera, ponieważ wymaga rzeczywistej ogólnej klasy impl w czasie wykonywania. To wciąż jest blisko tego, na co liczyłem.
Adam Levitt,
27

Jeśli rozumiem, potrzebujesz następującego kodu. (przekazywanie wyrażenia lambda przez parametr) Metoda

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
    }

Metoda wywołania

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

Możesz zrobić to samo w swojej klasie, zobacz przykład.

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;
    }

Metoda wywołania

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

Mam nadzieję, że to się przyda

Marinpietri
źródło
2
Czy możesz wyjaśnić, dlaczego potrzebujemy Compile()w .Where? Widziałem, że działa również bez tego.
Sнаđошƒаӽ
7

Wyrażenia lambda mają typ Action<parameters>(w przypadku, gdy nie zwracają wartości) lub Func<parameters,return>(w przypadku, gdy mają wartość zwracaną). W twoim przypadku masz dwa parametry wejściowe i musisz zwrócić wartość, więc powinieneś użyć:

Func<FullTimeJob, Student, FullTimeJob>
SztupY
źródło
5

Należy użyć typu delegata i określić go jako parametr polecenia. Możesz użyć jednego z wbudowanych typów delegatów - Actioni Func.

W twoim przypadku wygląda na to, że delegat pobiera dwa parametry i zwraca wynik, więc możesz użyć Func:

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

Następnie możesz wywołać GetJobsmetodę przekazywania w instancji delegata. Może to być metoda, która pasuje do tego podpisu, anonimowego delegata lub wyrażenia lambda.

PS Powinieneś używać PascalCase do nazw metod - GetJobsnie getJobs.

devdigital
źródło