135

I have a lambda expression that I'd like to be able to pass around and reuse. Here's the code:

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

The key here, is I want to be able to pass the lambda expression that I'm using here into the method that's calling this code, so I can reuse it. The lambda expression is the second argument inside my .Query method. I'm assuming I'd want to use an Action or Func, but I'm not quite sure what the syntax is for this or how it quite works. Can someone please give me an example?

3
  • 3
    Make the parameter an Action or a Func. Commented Jan 12, 2013 at 20:27
  • Right, that's what I thought... can you show me an example of how I'd do this? Commented Jan 12, 2013 at 20:28
  • possible duplicate of C# lambda expressions as function arguments Commented Jul 3, 2013 at 1:57

4 Answers 4

148

Use a Func<T1, T2, TResult> delegate as the parameter type and pass it in to your 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>();   
  }  
}

You would call it:

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

Or assign the lambda to a variable and pass it in.

Sign up to request clarification or add additional context in comments.

5 Comments

This looks very good, and how would I define the lambda OUTSIDE of this getJobs method? In other words, what's the line before the call to getJobs() look like to define the lambda?
@AdamLevitt - Same way you have with your example code. Will add to answer.
Also, can the function parameters be dynamic in anyway?
@AdamLevitt - you can make the function generic, though if you want different numbers of parameters on the lambdas, you will need overloads.
Right. What I'd actually like is to be able to pass in different implementations of the IJob interface, but that won't work with Dapper's Query<> because it requires the actual generic impl class at run time. This is still pretty close to what I was hoping for.
34

If I understand you need following code. (passing expression lambda by parameter) The Method

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
    }

Calling method

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

You can do the same in their class, see this is example.

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

Calling method

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

I hope this is useful

2 Comments

Can you explain why we need the Compile() in the .Where? I have seen it works without that too.
I think it is unnecessary. I think it should just be predicate. The Compile() would compile it to a Func<> and force it to loop through the entire list, row by row which is probably not what we want. ( see these answers ) for explanations.
11

Lambda expressions have a type of Action<parameters> (in case they don't return a value) or Func<parameters,return> (in case they have a return value). In your case you have two input parameters, and you need to return a value, so you should use:

Func<FullTimeJob, Student, FullTimeJob>

Comments

6

You should use a delegate type and specify that as your command parameter. You could use one of the built in delegate types - Action and Func.

In your case, it looks like your delegate takes two parameters, and returns a result, so you could use Func:

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

You could then call your GetJobs method passing in a delegate instance. This could be a method which matches that signature, an anonymous delegate, or a lambda expression.

P.S. You should use PascalCase for method names - GetJobs, not getJobs.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.