详解C# Lambda表达式的动态生成

C# Lambda表达式的概念大家一定已经清楚了,那么如何动态生成C# Lambda表达式呢?具体的操作是什么呢?有什么需要注意的呢?那么本文就向你介绍具体的内容。
首页 新闻资讯 行业资讯 详解C# Lambda表达式的动态生成

对于C# Lambda的理解我们在之前的文章中已经讲述过了,那么作为Delegate的进化使用,为了让代码简洁和优雅的呈现,C# Lambda表达式的使用功不可灭,那么依托外部条件如何动态构建C# Lambda表达式呢。下面让我们来具体的看看实施。

或许你会奇怪这个需求是如何产生的…… 首先,Lambda 在 DLinq 中承担了以往 T-SQL 的部分角色;其次,在数据库设计中,我们往往需要依据外部未知的动态条件组合来查询数据。而问题在于作为一种静态语言,我们显然无法用动态语法或者拼接字符串的方法来创建一个Delegate/Lambda,那么如何达到类似的目的呢?CodeDom?Emit?或许最佳的选择是 System.Linq.Expressions.Expression。

1、首先我们了解一个简单C# Lambda表达式的构成。

复制

i => i > 5
  • 1.

在这个表达式中,"i" 被称为 Parameter,"i > 5" 是 Body。我们可以对 Body 进行更进一步的分解,那么 "i > 5" 分别包含参数(i)、操作符(>)以及一个常数(5)。所有这些通过特定顺序的组合,从而构建一个完整的 Lambda 表达式。

2、我们通过一些例子,来学习如何动态构建C# Lambda表达式

动态构建C# Lambda表达式例子1

复制

var ints =   new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };  //var r = ints.Where(i => i > 5);   // 要实现的表达式   // 创建参数 i  var parameter =   Expression.Parameter(typeof(int), "i");   // 创建常量5  var constant =   Expression.Constant(5);   // 创建比较表达式 i > 5  var bin =   Expression.GreaterThan(parameter, constant);   // 获取Lambda表达式  var lambda =   Expression.Lambda<Func<int, bool>>(bin, parameter);   // 通过 Compile 方法获取 Delegate  var _r = ints.Where(lambda.Compile());
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

在代码中设置断点,我们可以看到调试器中显示的表达式信息。

图1

.NET FX 3.5 中为 Lambda 新增了一些委托类型。

(1) 用于处理无返回数据的 Action。

复制

public delegate void   Action()  public delegate void   Action<T> (T arg)  public delegate void   Action<T1, T2> (T1 arg1, T2 arg2)  public delegate void   Action<T1, T2, T3>   (T1 arg1, T2 arg2, T3 arg3)  public delegate void   Action<T1, T2, T3, T4>   (T1 arg1, T2 arg2, T3 arg3, T4 arg4)
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

(2) 用于处理带返回数据的 Func。

复制

public delegate TResult   Func<TResult> ()  public delegate TResult  Func<T, TResult> (T arg)  public delegate TResult   Func<T1, T2, TResult>   (T1 arg1, T2 arg2)  public delegate TResult   Func<T1, T2, T3, TResult>   (T1 arg1, T2 arg2, T3 arg3)  public delegate TResult   Func<T1, T2, T3, T4, TResult>   (T1 arg1, T2 arg2, T3 arg3, T4 arg4)
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

我们还可以进行更复杂的组合。

动态构建C# Lambda表达式例子2

复制

var ints =   new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };  // var r =   ints.Where(i => i > 5 && i <= 7);   // 要实现的表达式   // 创建参数 i  var parameter =   Expression.Parameter(typeof(int), "i");   // 创建表达式 i > 5   var con1 =   Expression.Constant(5);  var bin1 =   Expression.GreaterThan(parameter, con1);   // 创建表达式 i <= 7  var con2 =   Expression.Constant(7);  var bin2 =   Expression.LessThanOrEqual(parameter, con2);   // 组合两个表达式  var body =   Expression.And(bin1, bin2);   // 获取 Lambda 表达式  var lambda =   Expression.Lambda<Func<int, bool>>(body, parameter);   var _r = ints.Where(lambda.Compile());
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

在例子2中,我们对复杂的表达式进行了分解,并使用 And 完成多个表达式的组装,由此我们可以创建更加复杂的逻辑组合,比如例子3。#p#

动态构建C# Lambda表达式例子3

复制

var ints =   new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };  // var r =   ints.Where(i => (i > 5 && i <= 7) || (i == 3));   // 要实现的表达式   // 创建参数 i  var parameter =   Expression.Parameter(typeof(int), "i");   // 创建表达式 i > 5  var con1 =   Expression.Constant(5);  var bin1 =   Expression.GreaterThan(parameter, con1);   // 创建表达式 i < 7  var con2 =   Expression.Constant(7);  var bin2 =   Expression.LessThanOrEqual(parameter, con2);   // 创建表达式 i == 3  var con3 =   Expression.Constant(3);  var bin3 =   Expression.Equal(parameter, con3);   // 组合 i > 5 && i <= 7  var body =   Expression.And(bin1, bin2);   // 组合 ( i > 5 && i <= 7) OR (i == 3)  body = Expression.Or(body, bin3);   var lambda =   Expression.Lambda<Func<int, bool>>  (body, parameter);  var _r = ints.Where(lambda.Compile());
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

  • 36.

  • 37.

  • 38.

  • 39.

我们继续看几个常见的例子。

动态构建C# Lambda表达式例子4

复制

var ints =   new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };  //var r = ints.Select(i => i % 2 == 0 ? i : 0);   // 要实现的表达式   // 创建参数 i  var parameter =   Expression.Parameter(typeof(int), "i");   // 创建表达式 i % 2  var con1 =   Expression.Constant(2);  var bin1 =   Expression.Modulo(parameter, con1);   // 创建表达式 (i % 2) == 0  var con2 =   Expression.Constant(0);  var bin2 =   Expression.Equal(bin1, con2);   // 创建表达式 IIF(((i % 2) = 0), i, 0)  var bin3 =   Expression.Condition  (bin2, parameter, Expression.Constant(0));   var lambda =   Expression.Lambda<Func<int, int>>(bin3, parameter);  var _r = ints.Select(lambda.Compile());
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

动态构建C# Lambda表达式例子5

复制

var ints =   new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };  // Array.ForEach<int>(ints, i => Console.WriteLine(i));   // 要实现的表达式   // 创建参数i  var parameter =   Expression.Parameter(typeof(int), "i");   // 获取 Console.WriteLine MethodInfo  MethodInfo method =   typeof(Console).GetMethod(  "WriteLine", new Type[] { typeof(int) });   // 创建表达式   var call = Expression.Call(method, parameter);   var lambda =   Expression.Lambda<Action<int>>(call, parameter);  Array.ForEach<int>(  ints, lambda.Compile());
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

是该花点时间去好好研究一下 System.Linq.Expressions Namespace 了……

动态构建C# Lambda表达式的基本内容就向你介绍到这里,希望那个对你了解和掌握使用动态构建C# Lambda表达式有所帮助。

【编辑推荐】

  1. LINQ to SQL删除实现体会小结

  2. LINQ删除记录的操作实现

  3. 实现LINQ删除数据的巧妙方法

  4. 详解实现LINQ to SQL删除行

  5. C# Lambda Expression概念浅析