如何使用Expression(Of TDelegate).Update方法

发布于 2024-12-17 23:47:59 字数 964 浏览 2 评论 0 原文

我已经使用 Lambda 表达式构建了一个存储库来过滤我的实体集合。作为该方法的参数,我发送 Expression>指数。但在方法内部,我想用一些全局过滤器更新相同的表达式。我可以看到表达式对象本身有一个 Update 方法,但我无法弄清楚它是如何实现的(并且在搜索网络时找不到任何内容)。

exp.Update(exp.Body, ???);

谁能举个例子吗??

编辑:方法的定义: http://msdn.microsoft.com/en- us/library/ee378255.aspx

编辑2:这是我的代码(我尝试使用 .And):

Expression<Func<Case, bool>> newExp = c => c.CaseStatusId != (int)CaseStatus.Finished
var binExp = Expression.And(exp.Body, newExp.Body);
ParameterExpression paramExp = Expression.Parameter(typeof(Expression<Func<Case, bool>>), "c");
return repository.Where(Expression.Lambda<Expression<Func<Case, bool>>>(binExp, 
    new[] { paramExp }).Compile()).ToArray();

它失败并出现以下 ArgumentException:必须派生 Lambda 类型参数来自 System.Delegate

I have built a repository using Lambda expressions to filter my entity collections. As a parameter to the method I'm sending Expression<Func<Case, bool>> exp. But inside the method I would like to update that same expression with some global filters. I can see that the expression object itself got an Update method, but I can't figure out how it is implemented (and cannot find anything while searching the net).

exp.Update(exp.Body, ???);

Could anyone give an example??

EDIT: Definition of the method: http://msdn.microsoft.com/en-us/library/ee378255.aspx

EDIT2: This is my code (where I try to use .And):

Expression<Func<Case, bool>> newExp = c => c.CaseStatusId != (int)CaseStatus.Finished
var binExp = Expression.And(exp.Body, newExp.Body);
ParameterExpression paramExp = Expression.Parameter(typeof(Expression<Func<Case, bool>>), "c");
return repository.Where(Expression.Lambda<Expression<Func<Case, bool>>>(binExp, 
    new[] { paramExp }).Compile()).ToArray();

It fails with the following ArgumentException: Lambda type parameter must be derived from System.Delegate

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

焚却相思 2024-12-24 23:47:59

我认为 Update 方法在这里无法为您提供帮助。它只创建一个新的 lambda,但不会用新参数更新原始参数,您必须手动执行此操作。
我建议让访问者替换参数,然后您可以将表达式放在一起。

总的来说,你会得到类似的东西:

    private Case[] getItems(Expression<Func<Case, bool>> exp)
    {
        return repository.Where(AddGlobalFilters(exp).Compile()).ToArray();
    }

    private Expression<Func<Case, bool>> AddGlobalFilters(Expression<Func<Case, bool>> exp)
    {
        // get the global filter
        Expression<Func<Case, bool>> newExp = c => c.CaseStatusId != (int)CaseStatus.Finished;

        // get the visitor
        var visitor = new ParameterUpdateVisitor(newExp.Parameters.First(), exp.Parameters.First());
        // replace the parameter in the expression just created
        newExp = visitor.Visit(newExp) as Expression<Func<Case, bool>>;

        // now you can and together the two expressions
        var binExp = Expression.And(exp.Body, newExp.Body);
        // and return a new lambda, that will do what you want. NOTE that the binExp has reference only to te newExp.Parameters[0] (there is only 1) parameter, and no other
        return Expression.Lambda<Func<Case, bool>>(binExp, newExp.Parameters);
    }


    /// <summary>
    /// updates the parameter in the expression
    /// </summary>
    class ParameterUpdateVisitor : ExpressionVisitor
    {
        private ParameterExpression _oldParameter;
        private ParameterExpression _newParameter;

        public ParameterUpdateVisitor(ParameterExpression oldParameter, ParameterExpression newParameter)
        {
            _oldParameter = oldParameter;
            _newParameter = newParameter;
        }

        protected override Expression VisitParameter(ParameterExpression node)
        {
            if (object.ReferenceEquals(node, _oldParameter))
                return _newParameter;

            return base.VisitParameter(node);
        }
    }

I don't think the Update method can help you here. It only creates a new lambda, but does not update the original parameters with the new one, you have to do it manually.
I'd recommend having a visitor that replaces the parameter, then you can And the expressions together.

In total you would get something like:

    private Case[] getItems(Expression<Func<Case, bool>> exp)
    {
        return repository.Where(AddGlobalFilters(exp).Compile()).ToArray();
    }

    private Expression<Func<Case, bool>> AddGlobalFilters(Expression<Func<Case, bool>> exp)
    {
        // get the global filter
        Expression<Func<Case, bool>> newExp = c => c.CaseStatusId != (int)CaseStatus.Finished;

        // get the visitor
        var visitor = new ParameterUpdateVisitor(newExp.Parameters.First(), exp.Parameters.First());
        // replace the parameter in the expression just created
        newExp = visitor.Visit(newExp) as Expression<Func<Case, bool>>;

        // now you can and together the two expressions
        var binExp = Expression.And(exp.Body, newExp.Body);
        // and return a new lambda, that will do what you want. NOTE that the binExp has reference only to te newExp.Parameters[0] (there is only 1) parameter, and no other
        return Expression.Lambda<Func<Case, bool>>(binExp, newExp.Parameters);
    }


    /// <summary>
    /// updates the parameter in the expression
    /// </summary>
    class ParameterUpdateVisitor : ExpressionVisitor
    {
        private ParameterExpression _oldParameter;
        private ParameterExpression _newParameter;

        public ParameterUpdateVisitor(ParameterExpression oldParameter, ParameterExpression newParameter)
        {
            _oldParameter = oldParameter;
            _newParameter = newParameter;
        }

        protected override Expression VisitParameter(ParameterExpression node)
        {
            if (object.ReferenceEquals(node, _oldParameter))
                return _newParameter;

            return base.VisitParameter(node);
        }
    }
娇妻 2024-12-24 23:47:59
System.Linq.Expressions.Expression.And(exp.Body, newExpression.Body);

示例:

Expression<Func<int, bool>> f = p => true;
var a = Expression.And(f.Body, f.Body);
ParameterExpression pParam = Expression.Parameter(typeof(int), "p"); 
var b = (new int[] { 1, 2, 3 }).Where(Expression.Lambda<Func<int, bool>>(a,
        new ParameterExpression[] { pParam }).Compile());
System.Linq.Expressions.Expression.And(exp.Body, newExpression.Body);

exapmle:

Expression<Func<int, bool>> f = p => true;
var a = Expression.And(f.Body, f.Body);
ParameterExpression pParam = Expression.Parameter(typeof(int), "p"); 
var b = (new int[] { 1, 2, 3 }).Where(Expression.Lambda<Func<int, bool>>(a,
        new ParameterExpression[] { pParam }).Compile());
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文