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

标签 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;}
}

现在您可以看到 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);
    }

最佳答案

这取决于你的表达式树到底有多复杂,但在大多数简单的情况下你可以这样做:

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

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

关于c# - 使用 ExpressionVisitor 从表达式中删除条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36746895/

相关文章:

c# - dotnet restore fail "Unable to resolve ' PCLLibrary' for '.NETCoreApp,Version=v1.0'。”

c# - 使用 Include() 和条件过滤器连接两个表

c# - 这个SQL可以在LINQ中完成吗?

c# - 通过覆盖 MessageReceived 在 LuisDialog 中自动翻译消息

c# - 我是作为服务运行的吗

c# - LINQ 中的 Smalldatetime ToString

c# - 适用于 Windows 应用程序的 Monobjc 和 Mac UI

linq - 如何使用 LINQ 将 xml 文件转换为对象

linq - 根据条件查看 IEnumerable<T> 是否包含项目的最快方法

.net - .NET 中的多态关联