在动态.NET表达式中使用括号

时间:2011-09-05 09:20:56

标签: .net dynamic linq-expressions

我有一个网格,用户可以填写集合上的“过滤器”。 用户必须填写一些列:

AndOr  Property  Comparator  Value

说,对于城市集合,它可以过滤

的城市
   -  Name       StartsWith  'a'
  AND Population     >       10000
  OR  Population     <       1000

我使用了动态PredicateBuilder,效果非常好,直到出现“括号”要求。

从上面的“查询”中可以看出,在结果集合中,我们将有城市 (Name.StartsWith'a' AND Population > 10000) OR (Population < 1000)

为了建立表达式
 Name.StartsWith'a' AND (Population > 10000 OR (Population < 1000) 我需要使用一些括号。

现在,过滤网格列已更改为

AndOr  LeftBracket  Property  Comparator  Value  RightBracket

.NET动态表达式库中是否有“Group”,“Open / CloseBracket”? 另一种实现它的方法是什么?

它们之间“链接”行的代码如下

Private Function GetMyObjectsDataSource() As IQueryable(Of MyObject)
  ' start without any filter, get it all '
  Dim predicate = PredicateBuilder.True(Of MyObject)()
  Dim filterExpression As Expression(Of Func(Of MyObject, Boolean)) = predicate

  For Each row In grdFilter.Rows
    Dim rowExpression = GetExpressionFromRow(Of MyObject)(row)
    Dim compOp As LogicalOperator = row.Cells(ColumnKeys.AndOr).Value

    If compOp = LogicalOperator.Or Then
      filterExpression = [Or](filterExpression, rowExpression)
    Else
      filterExpression = [And](filterExpression, rowExpression)
    End If
  Next row

  Dim myObjects As List(Of MyObject) = Me._Container.GetMyObjects()
  Dim result As IQueryable(Of MyObject) =
    myObjects.AsQueryable().Where(filterExpression)

  Return result
End Function

1 个答案:

答案 0 :(得分:4)

处理此问题的最佳方法是在表达式树中使用嵌套的子表达式。这可能涉及改变您解释用户输入的方式。基本上,只要遇到LeftBracket元素,就会递归地构建一个子表达式,直到当前作用域中的下一个RightBracket元素。然后,您将整个子表达式指定为当前操作中的节点。

通过查看问题中的代码示例,我怀疑最好的位置是“GetExpressionFromRow”函数。不幸的是,我不认为“GetExpressionFromRow”是您在问题中引用的代码库的一部分。

如果您可以更新您的问题以包含GetExpressionFromRow和依赖项,我可以尝试进一步检查并提供更具体的答案。

这种技术背后的基本算法称为递归下降解析器。请在此处查看一些常规信息:http://en.wikipedia.org/wiki/Recursive_descent_parser