2016-01-26 40 views
5

我有以下代碼:定義表達式的一部分,在C#中的變量

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

,並用它如下:

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

有什麼辦法來定義是這樣的:

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

我使用Expression<Func<T,bool>>將其用作我的linq to entities查詢中的where子句(EF代碼優先)。

+0

是'p'表達式>'還是'Func '? – gmiley

+0

不應該'c.Criteria = x.Name.StartWith(「SomeTexts」);'是'c.Criteria = x => x.Name.StartWith(「SomeTexts」);'? –

+0

@YacoubMassad:你是對的:) – Masoud

回答

2

您可以使用下面的輔助功能(一個也許可以給他們一個更好的名字,但是這並不重要):

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

讓我們看看如何樣表達

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

可以從兩個不同的部分構建。

如果你有

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

然後

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

,或者如果你有這樣的而不是

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

然後

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

如果你有兩個表達式,那麼你可以使用這兩個函數中的任何一個,因爲a.Bind(b)等於b.ApplyTo(a)

0

你必須定義類型變量明確的,但下面的代碼將幫助您解決您的方案:

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

有點點不表達簡單的解決辦法:

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

您還可以使用Func<>代替Expression<>MyClass

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

我在這裏看不到使用Expression的好處。如何直Func

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

然後......

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

我希望使用表達式>作爲我的Linq中的一個標準,以便首先在EF代碼中進行查詢。 – Masoud

0

如果你想要一個表達式,那麼你可以使用LinqKit做到以下幾點:

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是LinqKit提供的擴展方法這可以幫助你輕鬆地編寫表達式。

調用Expand方法後,c.Criteria將包含是完全一樣的,如果你這樣做的表達式:

c.Criteria = x => x.Name.StartsWith("asd"); 
相關問題