一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

.NET中lambda表达式合并问题及解决方法

时间:2026-09-16 09:30:01 编辑:袖梨 来源:一聚教程网

这篇文章主要介绍了.net lambda表达式合并问题,解决方法是自己构造一个新的表达式,构造表达式需要用到expression类,本文结合实例代码给大家详细介绍,需要的朋友可以参考下

解决方案:

//表达式Func<Report,bool> nameFilter = x=>x.Name == "test";Func<Report,bool> stateFilter = x=>x.State==1;//合并为Func<Report,bool> whereFilter = x=>x.Name == "test" && x.State==1;//调用DbContext.Report.Where(whereFilter);

完美解决

那怎么合并,当然得自己构造一个新的表达式,构造表达式需要用到Expression类,如果没有用过这个类,可以按照下面的方式来调试看看一个表达式转换为表达式树是怎么样的。

TestExpression(x=>x.Name == "test",x=>x.State==1);public static void TestExpression(Expression<Func<Report, bool>> left,Expression<Func<Report, bool>> right){ //调试查看expression对象var bodyLeft = left.Body;//这个就是x.Name == "test"var bodyRight = right.Body;//这个就是x.State==1}

好,这里我们能获取到表达式的Body,然后使用Expression类能很好的合并两个表达式的body

var andAlso = Expression.AndAlso(bodyLeft ,bodyRight);//x.Name == "test" && x.State==1

这样还不行,这两个表达式是两个不同的委托对象,他们的参数x也是两个不同的对象,合并了又没完全合并

这就需要用到ExpressionVisitor类来递归表达式树,把两个表达式的参数替换为同一个参数。

/// <summary>/// 替换表达式参数/// </summary>public class ReplaceExpressionVisitor : ExpressionVisitor{private Expression _leftParameter;public ReplaceExpressionVisitor(Expression leftParameter){_leftParameter= leftParameter;}protected override Expression VisitParameter(ParameterExpression node){return _leftParameter;}}

最终

TestExpression(x=>x.Name == "test",x=>x.State==1);public static void TestExpression(Expression<Func<Report, bool>> left,Expression<Func<Report, bool>> right){ //调试查看expression对象var bodyLeft = left.Body;//这个就是x.Name == "test"var bodyRight = right.Body;//这个就是x.State==1var leftParameter = left.Parameters[0];//表达式递归访问var visitor =new ReplaceExpressionVisitor(leftParameter);//替换参数bodyRight = visitor.Visit(bodyRight);//合并表达式var expression = Expression.AndAlso(bodyLeft , bodyRight);//构建表达式var whereExpression= Expression.Lambda<Func<Report, bool>>(expression , left.Parameters);//编译表达式var whereFilter = whereExpression.Compile();//使用DbContext.Report.Where(whereFilter);}

正想给小老弟显摆一下的时候,他又去写其他骚代码了

骚不过骚不过,完善一下列子,下面是完整的代码

小嫩手不想动的小伙伴可以直接nuget上查找DynamicExpression.Core,直接使用

更多源码看本人github

/// <summary>/// 替换表达式参数/// </summary>public class ReplaceExpressionVisitor : ExpressionVisitor{private Dictionary<Expression, Expression> _parameters;public ReplaceExpressionVisitor(Dictionary<Expression,Expression> parameters){_parameters = parameters;}protected override Expression VisitParameter(ParameterExpression node){if (_parameters.TryGetValue(node, out Expression _newValue)){return _newValue;}return base.Visit(node);}}
/// <summary>/// 表达式扩展/// </summary>public static class ExpressionExtension{/// <summary>/// 使用AndAlso合并表达式/// </summary>/// <param name="exprs"></param>/// <returns></returns>public static Expression<T> AndAlso<T>(this IList<Expression<T>> exprs){if (exprs.Count == 0) return null;if (exprs.Count == 1) return exprs[0];var leftExpr = exprs[0];var left = leftExpr.Body;for (int i = 1; i < exprs.Count; i++){var expr = exprs[i];var visitor = GetReplaceExpressionVisitor(expr.Parameters, leftExpr.Parameters);var right = visitor.Visit(expr.Body);left = Expression.AndAlso(left, right);}return Expression.Lambda<T>(left, leftExpr.Parameters);}/// <summary>/// 使用AndAlso合并表达式/// </summary>/// <typeparam name="T"></typeparam>/// <param name="left"></param>/// <param name="right"></param>/// <returns>left AndAlso right</returns>public static Expression<T> AndAlso<T>(this Expression<T> left, Expression<T> right){return AndAlso(new List<Expression<T>>() { left, right });}/// <summary>/// 使用OrElse合并表达式/// </summary>/// <typeparam name="T"></typeparam>/// <param name="exprs"></param>/// <returns></returns>public static Expression<T> OrElse<T>(this IList<Expression<T>> exprs){if (exprs.Count == 0) return null;if (exprs.Count == 1) return exprs[0];var leftExpr = exprs[0];var left = leftExpr.Body;for (int i = 1; i < exprs.Count; i++){var expr = exprs[i];var visitor = GetReplaceExpressionVisitor(expr.Parameters, leftExpr.Parameters);var right = visitor.Visit(expr.Body);left = Expression.OrElse(left, right);}return Expression.Lambda<T>(left, leftExpr.Parameters);}/// <summary>/// 使用OrElse合并表达式/// </summary>/// <typeparam name="T"></typeparam>/// <param name="left"></param>/// <param name="right"></param>/// <returns>left OrElse right</returns>public static Expression<T> OrElse<T>(this Expression<T> left, Expression<T> right){return OrElse(new List<Expression<T>>() { left, right });}/// <summary>/// 构建visitor/// </summary>/// <param name="oldParameters"></param>/// <param name="newParameters"></param>/// <returns></returns>private static ReplaceExpressionVisitor GetReplaceExpressionVisitor(ReadOnlyCollection<ParameterExpression> oldParameters, ReadOnlyCollection<ParameterExpression> newParameters){Dictionary<Expression, Expression> dic = new Dictionary<Expression, Expression>();for (int i = 0; i < oldParameters.Count; i++){dic.Add(oldParameters[i],newParameters[i]);}return new ReplaceExpressionVisitor(dic);}}

使用

string connectString = "Data Source=.;Initial Catalog=RportTest;Integrated Security=True";var optionsBuilder = new DbContextOptionsBuilder<TestContext>();optionsBuilder.UseSqlServer(connectString);using (TestContext ctx = new TestContext(optionsBuilder.Options)){Expression<Func<ReportData, bool>> epxr1 = report => report.ID == 2023;Expression<Func<ReportData, bool>> epxr2 = report => report.Name == "test1";var epxr3 = new List<Expression<Func<ReportData, bool>>>() { epxr1, epxr2 };var andPredicate = epxr3.AndAlso();var andQuery = ctx.ReportData.Where(andPredicate);string andSql = andQuery.ToQueryString();var andResult = andQuery.ToList();var orPredicate = epxr3.OrElse();var orQuery = ctx.ReportData.Where(orPredicate);string orSql = orQuery.ToQueryString();var orResult = orQuery.ToList();}

到此这篇关于.netlambda表达式合并的文章就介绍到这了,更多相关.netlambda表达式内容请搜索一聚教程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持一聚教程网!

热门栏目