【问题标题】:How to use Expression(Of TDelegate).Update Method如何使用 Expression(Of TDelegate).Update 方法
【发布时间】:2011-11-24 12:47:59
【问题描述】:

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

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

谁能举个例子?

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

EDIT2:这是我的代码(我尝试使用 .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 派生

【问题讨论】:

  • 注意:Expression(Of TDelegate) 是 VB 语法。在documentation page 的顶部,您可以切换到 C#。

标签: c# lambda expression


【解决方案1】:

我不认为Update 方法可以帮助你。它只会创建一个新的 lambda,但不会用新的参数更新原始参数,您必须手动完成。 我建议让访问者替换参数,然后您可以将表达式一起And

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

    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);
        }
    }

【讨论】:

  • 很抱歉没有“关闭”这个话题。它是通过改变业务逻辑来“解决”的......
【解决方案2】:
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());

【讨论】:

  • 你能澄清一下/举一个更具体的例子吗? .And() 方法返回一个 BinaryExpression 对象,我需要一个 Expression> 对象
  • 我得到“二元运算符 Add 没有为类型 'System.Boolean' 和 'System.Boolean' 定义。”尝试将其实现到我的代码中时出错。
  • 它偏离了方向而且我应该使用(昨天有点累)。有关我对 And 方法的测试的详细信息,请参阅我的原始帖子...
  • 替换 Expression.Lambda>> 为 Expression.Lambda>
  • 这给出了例外:“参数类型:'System.Func' 不能分配给系统类型'System.Linq.Expressions.Expression >'"
猜你喜欢
  • 1970-01-01
  • 2019-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多