2012-05-16 29 views
13

Tôi có hai biểu thức lambda:Làm cách nào để kết hợp hai biểu thức lambda mà không sử dụng phương thức Gọi?

Expression<Func<MyEntity, bool>> e1 = i=>i.FName.Contain("john");

Expression<Func<MyEntity, bool>> e2=i=>i.LName.Contain("smith"); 

i loại, xuất phát từ thực thể poco của tôi, mà không thể sử dụng với invoke. Tôi muốn kết hợp chúng trong thời gian chạy.

Tôi muốn kết hợp các biểu thức trong thời gian chạy trong một cách tương tự như:

Expression<Func<MyEntity, bool>> e3 = Combine(e1,e2); 
+0

Kết hợp * cách * - "và cũng"? –

+0

có, vàAlso. Tôi muốn kết hợp chúng trong thời gian chạy. – PickleRick

Trả lời

35

Vấn đề là bạn không thể chỉ "và"/"hoặc" cho họ, bởi vì bạn cần phải re-write các bên trong để thay đổi các thông số; nếu bạn sử dụng .Body từ e1, nhưng thông số từ e2, nó sẽ không hoạt động - vì .Body của e1 tham chiếu đến một cá thể tham số hoàn toàn không liên quan chưa được xác định. Đây là chi tiết rõ ràng nếu bạn sử dụng:

Expression<Func<MyEntity, bool>> e1 = i => i.FName.Contains("john"); 
Expression<Func<MyEntity, bool>> e2 = j => j.LName.Contains("smith"); 

(lưu ý sự khác biệt giữa e1 sử dụng ie2 sử dụng j)

Nếu chúng ta kết hợp chúng mà không cần viết lại các tham số, chúng ta sẽ nhận được vô nghĩa:

Expression<Func<MyEntity, bool>> combined = 
     i => i.FName.Contains("john") && j.LName.Contains("smith"); 

(woah .... where did j from from?)

HOWEVER; vấn đề là giống nhau bất kể tên tên của thông số: nó vẫn là một tham số khác.

Và vì biểu thức là bất biến, bạn không thể chỉ trao đổi nó "tại chỗ".

Bí quyết là sử dụng một "khách" để viết lại các nút, như vậy:

using System; 
using System.Linq.Expressions; 

class SwapVisitor : ExpressionVisitor 
{ 
    private readonly Expression from, to; 
    public SwapVisitor(Expression from, Expression to) 
    { 
     this.from = from; 
     this.to = to; 
    } 
    public override Expression Visit(Expression node) 
    { 
     return node == from ? to : base.Visit(node); 
    } 
} 

static class Program 
{ 
    static void Main() 
    { 
     Expression<Func<MyEntity, bool>> e1 = i => i.FName.Contains("john"); 
     Expression<Func<MyEntity, bool>> e2 = i => i.LName.Contains("smith"); 

     // rewrite e1, using the parameter from e2; "&&" 
     var lambda1 = Expression.Lambda<Func<MyEntity, bool>>(Expression.AndAlso(
      new SwapVisitor(e1.Parameters[0], e2.Parameters[0]).Visit(e1.Body), 
      e2.Body), e2.Parameters); 

     // rewrite e1, using the parameter from e2; "||" 
     var lambda2 = Expression.Lambda<Func<MyEntity, bool>>(Expression.OrElse(
      new SwapVisitor(e1.Parameters[0], e2.Parameters[0]).Visit(e1.Body), 
      e2.Body), e2.Parameters); 
    } 
} 
+0

+1 Wow - câu trả lời sâu sắc là gì. –

+0

Cảm ơn bạn đã đánh dấu! bạn đã thực hiện nó. nó hoạt động rất tốt. – PickleRick

Các vấn đề liên quan