2016-01-26 14 views
5

Ho seguente codice:Definire parte di un'espressione come una variabile in C#

public class MyClass<T> 
{ 
    Expression<Func<T,bool>> Criteria {get; set;} 
} 
public class Customer 
{ 
    //.. 
    public string Name {get; set;} 
} 

e usarlo come segue:

var c = new MyClass<Customer>(); 
c.Criteria = x.Name.StartWith("SomeTexts"); 

Esiste un modo per definire qualcosa di simile:

Ho utilizzato Expression<Func<T,bool>> per utilizzarlo come clausola where nella mia query linq to entities (prima il codice EF).

+0

È 'p' un 'espressione >' o un 'Func '? – gmiley

+0

Non dovrebbe 'c.Criteria = x.Name.StartWith (" SomeTexts ");' be 'c.Criteria = x => x.Name.StartWith (" SomeTexts ");'? –

+0

@YacoubMassad: hai ragione :) – Masoud

risposta

2

È possibile utilizzare le seguenti funzioni di assistenza (si potrebbe probabilmente dare loro un nome migliore , ma non è indispensabile):

public static class ExpressionUtils 
{ 
    public static Expression<Func<TOuter, TResult>> Bind<TOuter, TInner, TResult>(this Expression<Func<TOuter, TInner>> source, Expression<Func<TInner, TResult>> resultSelector) 
    { 
     var body = new ParameterExpressionReplacer { source = resultSelector.Parameters[0], target = source.Body }.Visit(resultSelector.Body); 
     var lambda = Expression.Lambda<Func<TOuter, TResult>>(body, source.Parameters); 
     return lambda; 
    } 

    public static Expression<Func<TOuter, TResult>> ApplyTo<TInner, TResult, TOuter>(this Expression<Func<TInner, TResult>> source, Expression<Func<TOuter, TInner>> innerSelector) 
    { 
     return innerSelector.Bind(source); 
    } 

    class ParameterExpressionReplacer : ExpressionVisitor 
    { 
     public ParameterExpression source; 
     public Expression target; 
     protected override Expression VisitParameter(ParameterExpression node) 
     { 
      return node == source ? target : base.VisitParameter(node); 
     } 
    } 
} 

Let vedere come l'espressione di esempio

c.Criteria = x => x.Name.StartsWith("SomeTexts"); 

può essere costruito da due parti differenti.

Se hai

Expression<Func<Customer, string>> e = x => x.Name; 

poi

c.Criteria = e.Bind(x => x.StartsWith("SomeTexts")); 

o se si dispone di questo, invece

Expression<Func<string, bool>> e = x => x.StartsWith("SomeTexts"); 

poi

c.Criteria = e.ApplyTo((Customer x) => x.Name); 

Se si dispone di entrambe le espressioni, è possibile utilizzare una delle due funzioni, poiché a.Bind(b) equivale a b.ApplyTo(a).

0

È necessario definire il tipo di codice esplicito ma la prossima variabile sarà aiuterà a risolvere lo scenario:

// define new expression that get an Order object and returns string value 
Expression<Func<Order, string>> p = x => x.Customer.Name; 
var c = new MyClass<Order>(); 

// Compile the expression to the Func then invoke it and call extra criteria 
c.Criteria = o => p.Compile().Invoke(o).StartsWith("SomeText"); 

C'è po 'soluzione più semplice, senza espressioni:

Func<Order, string> p = x => x.Customer.Name; 
var c = new MyClass<Order>(); 
c.Criteria = o => p(o).StartsWith("SomeText"); 

È anche possibile utilizzare Func<> invece di Expression<> in MyClass:

public MyClass<T> 
{ 
    Func<T,bool> Criteria {get; set;} 
} 
0

Non vedo il vantaggio di utilizzare uno Expression qui. Che ne dici di una scala Func?

public class MyClass<T> 
{ 
    public Func<T, string, bool> Criteria { get; set; } 
} 

E poi ...

var myCustomer = new MyClass<Customer> 
{ 
    Criteria = (c, s) => c.Name.StartsWith(s) 
}; 

var customer = new Customer { Name = "Bob" }; 

var x = myCustomer.Criteria(customer, "B"); 
+0

Voglio usare Expression > come criterio nel mio Linq per interrogare prima il codice EF. – Masoud

0

Se vuoi un'espressione, quindi è possibile utilizzare LinqKit per effettuare le seguenti operazioni:

Expression<Func<Customer, string>> p = x => x.Name; 

var c = new MyClass<Customer>(); 

c.Criteria = x => p.Invoke(x).StartsWith("asd"); //Reuse p expression 

c.Criteria = c.Criteria.Expand(); 

Invoke è un metodo di estensione fornito da LinqKit che ti aiuta a comporre facilmente le espressioni.

Dopo aver invocato il metodo Expand, c.Criteria conterrebbe un'espressione che è esattamente lo stesso come se avete fatto questo:

c.Criteria = x => x.Name.StartsWith("asd"); 
Problemi correlati