2016-04-20 8 views
6

Sto provando a creare un provider LINQ su un'API Web ben definita con un modello ben definito. Sto seguendo queste procedure dettagliate:Rimuovere una condizione da un'espressione utilizzando un ExpressionVisitor

sono stato in grado di creare il provider di query che traduce l'espressione per l'URL desiderato e funziona abbastanza bene.

Ora ecco il prossimo passo che non riesco proprio a capire. Immaginate che una delle richieste restituisce un oggetto definito in questo modo:

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

Ora, come si può vedere la SomeOtherObjectId non è decorato con l'attributo JsonProperty, cioè perché non è parte della definizione dell'oggetto restituito, ma è necessario perché è il parametro da cui dipende la richiesta get. Ciò significa che un'espressione come la seguente:

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

è tradotto in qualcosa di simile:

blablabla/QualcheID/....

Ora le ricerche web API sono limitati a i parametri che si aspettano in modo che il filtro IsActive venga ignorato, quindi ho pensato che dopo aver ricevuto la risposta potrei usare la stessa espressione di un predicato in una query LINQ to Objects in modo che il resto dei filtri sia preso in considerazione ma per fare così avrei voluto per ricreare l'espressione senza il filtro ProjectID in quanto non esiste nel JSON restituita che viene deserializzato in oggetto, in modo che avrebbe dovuto diventare qualcosa di simile:

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

Allora posso fare qualcosa di simile

return deserializedObject.Where(modifiedExp); 

Sono stato alla ricerca di esempi su come farlo utilizzando un ExpressionVisitor ma non riesco proprio a capire come ricreare l'espressione senza il filtro che voglio rimosso.

Grazie per il vostro aiuto.

UPDATE:

Grazie ad entrambi Evk e MaKCbIMKo dal momento che con le loro risposte combinate ho avuto la soluzione finale, che io includo nella speranza che possa aiutare gli altri.

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

È necessario sapere come farlo nel caso generico o solo per l'espressione concreta fornita (o.SomeOtherObjectId == "someId" && o.IsActive)? – Evk

+0

@Evk: in questo caso se ParameterName == "SomeOtherObjectId" deve essere rimosso dall'espressione esistente lasciando il resto invariato, indipendentemente dall'aspetto dell'espressione. Non sono sicuro se questo risponda alla tua domanda. –

risposta

2

Dipende da come complesso vostro albero di espressione è davvero, ma nel caso in cui più semplici si può fare così:

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

Questo presuppone che il "SomeOtherObjectId == 'QualcheID'" L'espressione è un po ' "e "catena, quindi basta sostituirlo con" true "che rimuove il suo effetto.

poi si fa:

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

Se la vostra espressione potrebbe essere più complessa - questo esempio dovrebbe darvi un'idea di come gestire la cosa.

+0

Questo era esattamente quello che stavo cercando, mi mancava tra le altre cose "return Expression.Constant (true)". Grazie. –

2

Questo è un basic example su come modificare l'albero delle espressioni.

Sarà necessario creare il proprio ExpressionVisitor e configurarlo in modo da cercare le condizioni che utilizzano le proprietà che si desidera ignorare (ad esempio, l'attributo Json manca o da un diverso attributo).

Quindi cancellarli dalla struttura o sostituirli con l'espressione "sempre true" invece di controllare il valore della proprietà.

Inoltre, here è possibile trovare informazioni utili su ciò che si sta chiedendo.

+0

@MaKCblMKo - Purtroppo avevo già visto i riferimenti che hai menzionato ma mancavano ancora alcune cose per ottenere la soluzione. +1 per avermi dato l'idea di verificare l'attributo JSON al posto del nome dell'attributo che rende la soluzione più generica. –

Problemi correlati