簡體   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