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

Ser*_*ero 7 c# linq

我正在尝试使用定义良好的模型为定义良好的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;}
}
Run Code Online (Sandbox Code Playgroud)

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

Expression<Func<SomeObject, bool>> exp = o => o.SomeOtherObjectId == "someId" && o.IsActive;
Run Code Online (Sandbox Code Playgroud)

被翻译成如下:

blablabla/someId/....

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

Expression<Func<SomeObject, bool>> modifiedExp = o => o.IsActive;
Run Code Online (Sandbox Code Playgroud)

那么我可以做点什么

return deserializedObject.Where(modifiedExp);
Run Code Online (Sandbox Code Playgroud)

我一直在搜索如何使用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);
    }
Run Code Online (Sandbox Code Playgroud)

Evk*_*Evk 2

这取决于表达式树的实际复杂程度,但在最简单的情况下,您可以这样做:

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);
    }        
}
Run Code Online (Sandbox Code Playgroud)

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

然后你就可以:

var anotherExp = (Expression<Func<SomeObject, bool>>) new Visitor().Visit(exp);
Run Code Online (Sandbox Code Playgroud)

如果您的表达式可能更复杂 - 这个示例应该让您了解如何处理它。