2013-07-31 35 views
8

Nếu tôi có một biểu hiện của một đại biểu chức năng mà phải mất một số thông số như sau:Giảm một biểu thức bằng cách nhập một tham số

Expression<Func<int, int, int, bool>> test = (num1, num2, num3) => num1 + num2 == num3; 

là có một chiều/làm thế nào tôi có thể thay thế một trong những giá trị (nói 5 cho num1) và nhận được sự biểu hiện tương đương với:

Expression<Func<int, int, bool>> test = (num2, num3) => 5 + num2 == num3; 

EDIT:

Ngoài ra cần phải giải quyết các loại phức tạp, ví dụ:

Expression<Func<Thing, int, int>> test = (thing, num2) => thing.AnIntProp + num2; 
+0

bản sao có thể có của [C# Linq vs. Currying] (http://stackoverflow.com/questions/8826266/c-sharp-linq-vs-currying) –

+2

trong khi tôi đã bỏ phiếu là trùng lặp, câu hỏi này thực sự có thể khác . Có lẽ bạn đang tìm kiếm cách sử dụng biểu thức khách truy cập để thay thế đối số với giá trị? (một cái gì đó dọc theo dòng [this] (http://stackoverflow.com/questions/11164009/using-a-linq-expressionvisitor-to-replace-primitive-parameters-with-property-ref)) –

+0

Không hoàn toàn. Tôi muốn được làm việc với các biểu thức. Tôi nghĩ rằng nó gần gũi hơn với [this] (http://stackoverflow.com/questions/11159697/replace-parameter-in-lambda-expression) hoặc [this] (http://stackoverflow.com/questions/5631070/currying -expressions-in-c-sharp) –

Trả lời

2

Câu trả lời của tôi là sử dụng khách truy cập biểu thức. (nhờ vào @ Alexei-levenkov để chỉ nó ra).

Câu trả lời cho tình huống cụ thể của tôi hơi khác so với ví dụ đơn giản tôi đã sử dụng trong câu hỏi. Nhưng, cho đầy đủ, đây là cách mà tôi đã làm nó:

public class ResolveParameterVisitor : ExpressionVisitor 
{ 
    private readonly ParameterExpression _param; 
    private readonly object _value; 

    public ResolveParameterVisitor(ParameterExpression param, object value) 
    { 
     _param = param; 
     _value = value; 
    } 

    public Expression ResolveLocalValues(Expression exp) 
    { 
     return Visit(exp); 
    } 

    protected override Expression VisitParameter(ParameterExpression node) 
    { 
     if (node.Type == _param.Type && node.Name == _param.Name 
      && node.Type.IsSimpleType()) 
     { 
      return Expression.Constant(_value); 
     } 

      return base.VisitParameter(node); 
    } 

    protected override Expression VisitLambda<T>(Expression<T> node) 
    { 
     var parameters = node.Parameters.Where(p => p.Name != _param.Name && p.Type != _param.Type).ToList(); 
     return Expression.Lambda(Visit(node.Body), parameters); 
    } 
} 

Lưu ý rằng IsSimpleType là một phần mở rộng tôi mượn từ this gist bởi jonothanconway.

Trong trường hợp của tôi, tôi muốn thay thế việc sử dụng loại phức tạp. ví dụ:

Expression<Func<Thing, int, bool>> test = (thing, num) => thing.AnIntProperty == num; 

Vì vậy, tôi đã ghi đè phương thức VisitMember. Đây vẫn là công việc đang tiến hành nhưng trông giống như sau:

 protected override Expression VisitMember(MemberExpression m) 
    { 
     if (m.Expression != null 
      && m.Expression.NodeType == ExpressionType.Parameter 
      && m.Expression.Type == _param.Type && ((ParameterExpression)m.Expression).Name == _param.Name) 
     { 
      object newVal; 
      if (m.Member is FieldInfo) 
       newVal = ((FieldInfo)m.Member).GetValue(_value); 
      else if (m.Member is PropertyInfo) 
       newVal = ((PropertyInfo)m.Member).GetValue(_value, null); 
      else 
       newVal = null; 
      return Expression.Constant(newVal); 
     } 

     return base.VisitMember(m); 
    } 

Điều này sẽ chỉ giải quyết trường hoặc thuộc tính. Bước tiếp theo có thể là thêm hỗ trợ cho một phương thức (nhưng khi chúng có tham số chính, do đó sẽ mất thêm một số công việc ...)

EDIT: Giải pháp khách truy cập thành viên ở trên cũng sẽ không hỗ trợ truyền đối tượng vào một cuộc gọi phương thức. ví dụ. (x, thing) => x.DoSomething(thing) do đó cần phải sửa đổi để thực hiện điều đó.

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