Expression是否有办法在运行时优化

JusticeKnight 2015-12-22 11:04:27
如何将
Expression<Func<int,int>>func2 =i=>(new Func<int,int>(j=>j+1))(i)*(new Func<int,int>(j=>j+2))(i) ;
优化成
Expression<Func<int,int>>func2 =i=>(i+1)*(i+2);

因为在linq2sql里面, 第一个是会挂掉的, 而第二个是可以正常走
我尝试了Reduce, 但是并没有效果
接触Expression不多, 没什么经验, 先谢谢大家

---------------------------------------------------------------------------------

上面不能Reduce的原因知道了, 但是问题还没有解决:
如何使用
Expression<Func<int, int>> f1 = i => i + 1;
Expression<Func<int, int>> f2 = i => i + 2;
Expression<Func<int, int, int>> f3 = (i, j) => i * j;
在运行时构造出
Expression<Func<int, int>> f4 = i =>(i+1)*(i+2);

...全文
1339 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
JusticeKnight 2018-05-04
  • 打赏
  • 举报
回复
引用 5 楼 u012758945 的回复:
我上面是示例如何通过代码来生成一个Expression,如果真的要做到你那种效果,需要自己手动写一个ExpressionVisitor 解析表达式,参考#4,然后再通过二次构建生成新的表达式,这无疑会增加代码的复杂度且性能上大打折扣。如果还需要在这基础上实现动态化,花费的成本远达不到获得的收益。
那天去问了老外, 是用visitor来搞定了 https://stackoverflow.com/questions/34408179/linq-expression-calling-combines (话说这贴在linq版还在第二页, 不算挖坟吧)
JusticeKnight 2018-05-04
  • 打赏
  • 举报
回复
引用 5 楼 u012758945 的回复:
我上面是示例如何通过代码来生成一个Expression,如果真的要做到你那种效果,需要自己手动写一个ExpressionVisitor 解析表达式,参考#4,然后再通过二次构建生成新的表达式,这无疑会增加代码的复杂度且性能上大打折扣。如果还需要在这基础上实现动态化,花费的成本远达不到获得的收益。
已经解决啦
Lee_Y_K 2016-05-26
  • 打赏
  • 举报
回复
我上面是示例如何通过代码来生成一个Expression,如果真的要做到你那种效果,需要自己手动写一个ExpressionVisitor 解析表达式,参考#4,然后再通过二次构建生成新的表达式,这无疑会增加代码的复杂度且性能上大打折扣。如果还需要在这基础上实现动态化,花费的成本远达不到获得的收益。
  • 打赏
  • 举报
回复
试着写了个,表达式是出来了,但编译时报错说引用了未定义的参数j, 应该是需要把原表达式叶子节点中使用j的地方统一引用新的参数argsExp 这还只是简单考虑了BinaryExpression这种二元算术运算和LambdaExpression 实在是太麻烦了,的确不搞这种东西,而且也没碰到过表达式中引用两个相同定义的Func委托这种 动态解析,基本上实现个ExpressionVisitor是逃不掉的

static void Main(string[] args)
        {
            Expression<Func<int, int>> func2 = i => (new Func<int, int>(j => j + 1))(i) * (new Func<int, int>(j => j + 2))(i);
            var argsExp = new ParameterExpression[] { Expression.Parameter(func2.Parameters[0].Type, "j") };
            var binExp = func2.Body as BinaryExpression;
            if (binExp != null)
            {                
                Expression left = GetBlockExpression(binExp.Left),
                                    right = GetBlockExpression(binExp.Right);

                var newBodyExp = binExp.Update(left, null, right);                
                var newFunc = func2.Update(newBodyExp, argsExp);
                Console.WriteLine(newFunc);
                var funcTest = newFunc.Compile();
            }
            Console.Read();
        }

        static Expression GetBlockExpression(Expression part)
        {
            if (!(part is UnaryExpression))
            {
                var lambdaExp = part as LambdaExpression;
                if (lambdaExp != null)
                {
                    return lambdaExp.Body.Reduce();
                }
                var invokeExp = part as InvocationExpression;
                if (invokeExp != null)
                {
                    //如果是Lambda构建的委托调用
                    if (invokeExp.Expression.NodeType == ExpressionType.Lambda)
                    {
                        return GetBlockExpression(invokeExp.Expression);
                    }
                    return Expression.Block(invokeExp.Expression.Reduce());
                }
                throw new NotSupportedException(); /////////////////////////////
            }
            return part.Reduce();
        }
  • 打赏
  • 举报
回复
我只搞应用技术方向,不搞这个方向。如果搞这个,我就去尝试开发一个“艾尔法狗”去了,真的! 如果这是你的专业,你可以搞这方面研究。 这显然并不是把一个表达式打印成字符串那么简单,这是把一个符号表达式智能地重写为“等价的”其它表达式。 如果你的“优化”比较简单,可以参考各种逻辑程序设计的专著。
Lee_Y_K 2016-05-26
  • 打赏
  • 举报
回复
看一下是不是你想要的。

static void Main(string[] args)
{
ParameterExpression i = Expression.Parameter(typeof(int), "i");
BinaryExpression i_add_1 = Expression.Add(i, Expression.Constant(1, typeof(int)));
BinaryExpression i_add_2 = Expression.Add(i, Expression.Constant(2, typeof(int)));
BinaryExpression i1_multiply_i2 = Expression.Multiply(i_add_1, i_add_2);
Expression<Func<int, int>> expression = Expression.Lambda<Func<int, int>>(i1_multiply_i2, i);
//输出测试
Console.WriteLine(expression.ToString());
}

运行结果


拿到Expression之后你可以直接编译成 Func或者填入Linq2Sql里作为条件
SoulRed 2016-05-26
  • 打赏
  • 举报
回复
这个有预编译语句么?你可以试试。

8,497

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 LINQ
社区管理员
  • LINQ
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧