2008-09-10 32 views
11

Tôi muốn soạn kết quả của hai Biểu thức LINQ. Chúng tồn tại ở dạngLàm cách nào để soạn các Biểu thức LINQ hiện có

Expression<Func<T, bool>> 

Vì vậy, hai thứ tôi muốn tạo về cơ bản là đại biểu trên tham số (loại T) trả về giá trị boolean. Kết quả tôi muốn sáng tác sẽ là đánh giá logic của các boolean. Tôi có lẽ sẽ thực hiện nó như một phương pháp khuyến nông nên cú pháp của tôi sẽ là một cái gì đó như:

Expression<Func<User, bool>> expression1 = t => t.Name == "steve"; 
Expression<Func<User, bool>> expression2 = t => t.Age == 28; 
Expression<Func<User, bool>> composedExpression = expression1.And(expression2); 

Và sau này trong mã của tôi, tôi muốn đánh giá sự biểu hiện sáng tác

var user = new User(); 
bool evaluated = composedExpression.Compile().Invoke(user); 

Tôi đã chọc xung quanh với một vài ý tưởng khác nhau nhưng tôi sợ rằng nó phức tạp hơn tôi đã hy vọng. Làm thế nào được thực hiện?

Trả lời

17

Dưới đây là một ví dụ:

var user1 = new User {Name = "steve", Age = 28}; 
var user2 = new User {Name = "foobar", Age = 28}; 

Expression<Func<User, bool>> expression1 = t => t.Name == "steve"; 
Expression<Func<User, bool>> expression2 = t => t.Age == 28; 

var invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>()); 

var result = Expression.Lambda<Func<User, bool>>(Expression.And(expression1.Body, invokedExpression), expression1.Parameters); 

Console.WriteLine(result.Compile().Invoke(user1)); // true 
Console.WriteLine(result.Compile().Invoke(user2)); // false 

Bạn có thể tái sử dụng mã này thông qua phương pháp khuyến nông:

class User 
{ 
    public string Name { get; set; } 
    public int Age { get; set; } 
} 

public static class PredicateExtensions 
{ 
    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expression1,Expression<Func<T, bool>> expression2) 
    { 
    InvocationExpression invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>()); 

    return Expression.Lambda<Func<T, bool>>(Expression.And(expression1.Body, invokedExpression), expression1.Parameters); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
    var user1 = new User {Name = "steve", Age = 28}; 
    var user2 = new User {Name = "foobar", Age = 28}; 

    Expression<Func<User, bool>> expression1 = t => t.Name == "steve"; 
    Expression<Func<User, bool>> expression2 = t => t.Age == 28; 

    var result = expression1.And(expression2); 

    Console.WriteLine(result.Compile().Invoke(user1)); 
    Console.WriteLine(result.Compile().Invoke(user2)); 
    } 
} 
1

Tại sao bạn không chỉ sử dụng Expression.And và xử lý kết quả là BinaryExpression?

Expression<Func<T, bool>> expr1 = t => t.Name == "steve"; 
Expression<Func<T, bool>> expr2 = t => t.Age == 28; 
Expression composed = Expression.And(expr1.Body, expr2.Body); 

Bạn có thể dĩ nhiên bó này thành một lambda để có được chữ ký của bạn mong muốn nhưng điều này là tốn kém và chỉ nên được thực hiện lần, không nhiều lần:

Expression<Func<T, bool>> result = Expression.Lambda<Func<T, bool>>(
    expr, Expression.Parameter(typeof(T), "t") 
); 

/EDIT: Bạn có thể tất nhiên kết hợp lambdas như sau nhưng điều này liên quan đến compilations dư thừa và các cuộc gọi chức năng:

Expression<Func<string, bool>> z = t => expr1.Compile()(t) && expr2.Compile()(t); 

Thiệt hại, duy trì thời gian chết. Đã phải gõ toàn bộ bài đăng một lần nữa. : -/

/EDIT: quyền của aku. Bạn phải gọi riêng expr2, nếu không trình biên dịch sẽ không tìm thấy tham chiếu tham số.

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