繁体   English   中英

使用ExpressionVisitor从表达式中删除条件

[英]Remove a condition from an expression using an ExpressionVisitor

我正在尝试使用定义良好的模型为定义良好的Web API构建LINQ提供程序。 我正在关注这些演练:

我已经能够创建查询提供程序,将表达式转换为所需的URL,它工作得很好。

现在这是我无法弄清楚的下一步。 想象一下,其中一个请求返回一个如下定义的对象:

[JsonObject]
public class SomeObject
{
   [JsonProperty(PropertyName = "id")]
   public string Id {get;set;}
   [JsonProperty(PropertyName = "name")]
   public string Name {get;set;}
   [JsonProperty(PropertyName = "is_active")]
   public bool IsActive {get;set;}

   public string SomeOtherObjectId {get;set;}
}

现在您可以看到SomeOtherObjectId未使用JsonProperty属性进行修饰,这是因为它不是返回的对象定义的一部分,但它是必需的,因为它是get请求所依赖的参数。 这意味着表达式如下:

Expression<Func<SomeObject, bool>> exp = o => o.SomeOtherObjectId == "someId" && o.IsActive;

被翻译成如下:

blablabla / someId / ....

现在Web API搜索受限于他们期望的参数,因此IsActive过滤器将被忽略所以我认为在收到响应后我可以在LINQ to Objects查询中使用相同的表达式作为谓词,所以其余的过滤器都是考虑到但是为了这样做,我将不得不重新创建没有ProjectId过滤器的表达式,因为它在返回的JSON中不存在被反序列化到对象中,所以它必须变成类似于:

Expression<Func<SomeObject, bool>> modifiedExp = o => o.IsActive;

那么我可以做点什么

return deserializedObject.Where(modifiedExp);

我一直在寻找如何使用ExpressionVisitor执行此操作的示例,但我无法理解如何在没有我想要删除的过滤器的情况下重新创建表达式。

谢谢您的帮助。

更新:

感谢EvkMaKCbIMKo,因为他们的综合答案我得到了最终的解决方案,我希望它可以帮助其他人。

protected override Expression VisitBinary(BinaryExpression node)
    {
        if (node.NodeType != ExpressionType.Equal) return base.VisitBinary(node);

        if (new[] { node.Left, node.Right }
            .Select(child => child as MemberExpression)
            .Any(memberEx => memberEx != null && memberEx.Member.CustomAttributes.All(p => p.AttributeType.Name != "JsonPropertyAttribute")))
        {
            return Expression.Constant(true);
        }

        return base.VisitBinary(node);
    }

以下是有关如何修改表达式树的基本示例

您将需要创建自己的ExpressionVisitor并对其进行配置,以查找使用您要跳过的属性的条件(例如,缺少Json属性或由不同的属性)。

然后只需从树中删除它们或用'always true'表达式替换,而不是检查属性值。

此外,您还可以在这里找到有关您所要求的有用信息。

这取决于表达式树的复杂程度,但在大多数情况下,您可以这样做:

class Visitor : ExpressionVisitor {
    protected override Expression VisitBinary(BinaryExpression node) {
        // SomeOtherObjectId == "someId"
        if (node.NodeType == ExpressionType.Equal) {
            foreach (var child in new[] {node.Left, node.Right}) {
                var memberEx = child as MemberExpression;
                if (memberEx != null && memberEx.Member.Name == "SomeOtherObjectId") {
                    // return True constant
                    return Expression.Constant(true);
                }
            }
        }
        return base.VisitBinary(node);
    }        
}

假设您的“SomeOtherObjectId ==”someId“”表达式位于某个“和”链上,因此您只需将其替换为“true”即可消除其效果。

然后你做:

var anotherExp = (Expression<Func<SomeObject, bool>>) new Visitor().Visit(exp);

如果你的表达式可能更复杂 - 这个例子应该让你知道如何处理它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM