微小代码

(代码,思想)=>软件

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

有时我们会碰到这样的状况,就是要把两个LambdaExpression合并起来变成一个LambdaExpression.

例如我们有如下两个用来筛选DataRow的表达式:


Expression<Func<DataRow, bool>> exp1 = r => r["name"].ToString() == "Rose";
Expression<Func<DataRow, bool>> exp2 = r => (int)r["age"] > 20;

 

那现在我们想即根据name又根据age来筛选呢,也就是说我们想要这样的表达式:

Expression<Func<DataRow, bool>> exp1 = r => r["name"].ToString() == "Rose" && (int)r["age"]>20;

很容易想到,可以用Expression.AndAlso来做,即

var newExp = Expression.Lambda(Expression.AndAlso(exp1.Body, exp2.Body),
Expression.Parameter(typeof (DataRow), "r"));

一切看起来很美好;p

但是接下来我们试图去compile时就会出错了,

 

这个错误就是由于两个LambdaExpression的Body引用的是两个不同的parameter instance,尽管parameter 的名字看起来是一样的。关于这个错误这篇stackoverflow文章说的很好:http://stackoverflow.com/questions/10613514/how-can-i-combine-two-lambda-expressions-without-using-invoke-method

并且这篇文章也很出了一个基于ExpressionVisitor的解决方案,这个解决方案很棒并且切中了要点。但我觉得实现不是很直观也,我的另一个解决方案是实现别一个ParameterReplacementVisitor。

代码如下:

public class ParameterReplacementVisitor : ExpressionVisitor
        {
            private readonly ParameterExpression _parameter;

            public ParameterReplacementVisitor(ParameterExpression parameter)
            {
                _parameter = parameter;
            }

            public ParameterExpression Parameter
            {
                get { return _parameter; }
            }

            protected override Expression VisitParameter(ParameterExpression node)
            {
                if (node.Name == _parameter.Name)
                {
                    return _parameter;
                }

                return base.VisitParameter(node);
            }
        }

 

这样很容易理解,并且采用的策略很简单,就是根据Parameter Name来把parameter 统一替换成给定的parameter,问题解决。

 测试代码

posted on 2016-09-07 14:56  微小代码  阅读(5824)  评论(3编辑  收藏  举报