C# 将 Lambda 表达式作为方法参数传递

Posted

技术标签:

【中文标题】C# 将 Lambda 表达式作为方法参数传递【英文标题】:C# Pass Lambda Expression as Method Parameter 【发布时间】:2012-12-27 04:25:36 【问题描述】:

我有一个我希望能够传递和重用的 lambda 表达式。代码如下:

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

这里的关键是,我希望能够将我在此处使用的 lambda 表达式传递给调用此代码的方法,以便我可以重用它。 lambda 表达式是我的 .Query 方法中的第二个参数。我假设我想使用 Action 或 Func,但我不太确定它的语法是什么或它是如何工作的。谁能给我一个例子?

【问题讨论】:

将参数设为 Action 或 Func。 对,我就是这么想的……你能给我举个例子吗? C# lambda expressions as function arguments 的可能重复项 【参考方案1】:

使用Func&lt;T1, T2, TResult&gt; 委托作为参数类型并将其传递给您的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>();   
    

你会这样称呼它:

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

或者将 lambda 赋值给一个变量,然后将 it 传入。

【讨论】:

这看起来很不错,我将如何定义这个 getJobs 方法的 lambda OUTSIDE?换句话说,在 getJobs() 调用之前定义 lambda 的那一行是什么? @AdamLevitt - 与示例代码相同。将添加到答案。 另外,函数参数无论如何都可以是动态的吗? @AdamLevitt - 您可以将函数设为通用,但如果您希望 lambda 上的参数数量不同,则需要重载。 对。我真正想要的是能够传递 IJob 接口的不同实现,但这不适用于 Dapper 的 Query 因为它在运行时需要实际的通用 impl 类。这仍然非常接近我的期望。【参考方案2】:

如果我了解您需要以下代码。 (通过参数传递表达式 lambda) 方法

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
    

调用方法

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

你可以在他们的课堂上做同样的事情,看这个例子。

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;
    

调用方法

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

希望对你有用

【讨论】:

您能解释一下为什么我们需要.Where 中的Compile() 吗?我已经看到它在没有它的情况下也可以工作。 我觉得没必要。我认为应该只是predicateCompile() 会将其编译为 Func&lt;&gt; 并强制它逐行遍历整个列表,这可能不是我们想要的。 (请参阅 these answers )以获得解释。【参考方案3】:

Lambda 表达式的类型为Action&lt;parameters&gt;(如果它们不返回值)或Func&lt;parameters,return&gt;(如果它们有返回值)。在你的情况下,你有两个输入参数,你需要返回一个值,所以你应该使用:

Func<FullTimeJob, Student, FullTimeJob>

【讨论】:

【参考方案4】:

您应该使用委托类型并将其指定为您的命令参数。您可以使用其中一种内置委托类型 - ActionFunc

在您的情况下,您的委托似乎需要两个参数并返回一个结果,因此您可以使用Func

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

然后您可以调用您的 GetJobs 方法并传入一个委托实例。这可以是与该签名匹配的方法、匿名委托或 lambda 表达式。

附:您应该使用 PascalCase 作为方法名称 - GetJobs,而不是 getJobs

【讨论】:

以上是关于C# 将 Lambda 表达式作为方法参数传递的主要内容,如果未能解决你的问题,请参考以下文章

委托 lambda表达式浅显理解

将Lambda表达式作为参数传递并解析-在构造函数参数列表中使用Lambda表达式

使用 lambda 表达式代替 IComparer 参数

在 C# 中将 lambda 函数作为命名参数传递

C# 多线程传递多个参数

C# lambda 表达式作为函数参数