根据用户选择在运行时构建动态谓词

时间:2013-06-10 07:53:44

标签: c# dynamic lambda runtime

我正在构建一个表单来显示一个列表,该列表将根据我的WinForm应用程序中的用户条件进行过滤, 假设我有一个通用列表IList<Order>Order 有一些属性,如OrderIdCustomerNameCreationDate,...

public Class Order
{
 public string OrderId {get; set;}
 public string CustomerName {get; set;}
 public DateTime CreationDate {get; set;}
}

另外,我在表单中添加了一些控件可以过滤列表。一个TextBox OrderId另一个CustomerNameDateTimePickers CreationDate范围(FromDateTimePicker,ToDateTimePicker)。

我也将谓词变量定义为:

Func<Order, bool> predicate = null; 

现在如何根据用户输入值构建我的predicate

我试着写这段代码:

if (tbOrderId.Text != string.Empty)
{
   string orderId;
   predicate = t=>t.OrderId == orderId;
}
if(tbCustomerName.Text != string.Empty)
{
   string customer = tbCustomerName.Text;
   if(predicate!=null)
      predicate = predicate && (t=>t.CustomerName == customer);
   else
      predicate = (t=>t.CustomerName == customer);
}
....

但是我收到了这个错误:

Operator '&&' cannot be applied to operands of type 'System.Func<Order,bool>' and 'lambda expression'

1 个答案:

答案 0 :(得分:2)

您的代码无效,因为您实际上并未将&&应用于谓词的结果,而是将其应用于谓词本身。即使你是这样写的:

predicate = t => predicate(t) && t.CustomerName == customer;

它会编译,但你最终会得到无限递归。

为简单起见,您可以使用纯Linq(可以使用任何IEnumerable<T>)来执行此操作:

IEnumerable<Order> results = ... // all items

if (tbOrderId.Text != string.Empty)
{
   string orderId;
   results = results.Where(t => t.OrderId == orderId);
}

if (tbCustomerName.Text != string.Empty)
{
   string orderId;
   results = results.Where(t => t.CustomerName == customer);
}

或者使用表达式(适用于IQueryable<T>):

ParameterExpression parameter = Expression.Parameter(typeof(DateTime));
Expression predicate = Expression.Constant(true);

if (tbOrderId.Text != string.Empty)
{
   string orderId = tbOrderId.Text;
   Expression prop = Expression.PropertyOrField(parameter, "OrderId");
   Expression filter = Expression.Equal(prop, Expression.Constant(orderId));
   predicate = Expression.AndAlso(predicate, filter);
}

if(tbCustomerName.Text != string.Empty)
{
   string customer = tbCustomerName.Text;
   Expression prop = Expression.PropertyOrField(parameter, "CustomerName");
   Expression filter = Expression.Equal(prop, Expression.Constant(customer))
   predicate = Expression.AndAlso(predicate, filter);
}

Expression lambda = Expression.Lambda(predicate, parameter);
return results.Where(lambda);