【问题标题】:User defined filters/queries?用户定义的过滤器/查询?
【发布时间】:2010-12-27 22:23:09
【问题描述】:

我正在尝试找出一种方法,让我的应用程序的用户可以定义他们自己的查询或过滤器,这些查询或过滤器可以应用于集合。我想最终提供一个直观的用户界面来创建这些过滤器(见下图),但如果用户必须输入文本查询字符串,那么最初就可以了。我还需要能够将这些用户定义的查询序列化为一个字符串,以便我可以将它们与项目的其余信息一起保存。

用户界面示例 alt text http://dl.dropbox.com/u/113068/filterUI.jpg

我正在寻找可以从诸如数字条件(小于、大于)、字符串条件(包含、开始于、结束于)或布尔条件(对或错)。我还希望能够使用 OR、AND 和 NOT 等布尔逻辑对条件进行分组。

我开始绘制如何使用 NodeFilter、AbsNodeCondition、NodeStringCondition、NodeConditionOrJoin 等类从头开始执行此操作。但我觉得我正在重新发明轮子,尤其是当有可用的 Linq 之类的东西时,我没有机会花太多时间。

我能否允许用户在文本框中输入 Linq to objects 查询,然后以编程方式将字符串转换为可应用于我的集合的真正 Linq 查询?还是有其他方法可以让用户创建和保存查询?我还需要一种将过滤器/查询序列化为字符串的方法,以便我可以将其与其余程序信息一起保存。

【问题讨论】:

  • 示例 UI 的链接已损坏。可以上传新图片吗?

标签: c# linq collections filtering


【解决方案1】:

这不一定是理想的解决方案,但MetaLinq 项目为 LINQ 表达式类提供了可序列化的包装器。

这是一个示例,说明如何在往返序列化后重新创建和执行表达式。

首先我们将一个现有的lamba表达式序列化为一个xml文档。

var originalExpr = EditableExpression.CreateEditableExpression<string, bool>(
    str => str.Length > 3);
var serializer = new XmlSerializer(originalExpr.GetType());
string xml;

using (var writer = new StringWriter())
{
    serializer.Serialize(writer, originalExpr);
    xml = writer.ToString();
}

然后我们反序列化、解包并将其编译回一个委托,准备好执行。

EditableExpression newExpr;

using (var reader = new StringReader(xml))
{
    newExpr = (EditableExpression) serializer.Deserialize(reader);
}

var expr = (Expression<Func<string, bool>>) newExpr.ToExpression();
var items = new[] {"one", "two", "three"};
var result = items.Count(expr.Compile());
Debug.Assert(result == 1);

这就是序列化表达式的样子。

<EditableLambdaExpression xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <NodeType>Lambda</NodeType>
  <TypeName>System.Func`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</TypeName>
  <Body xsi:type="EditableBinaryExpression">
    <NodeType>GreaterThan</NodeType>
    <TypeName>System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</TypeName>
    <Left xsi:type="EditableMemberExpression">
      <NodeType>MemberAccess</NodeType>
      <Expression xsi:type="EditableParameterExpression">
        <NodeType>Parameter</NodeType>
        <TypeName>System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</TypeName>
        <Name>str</Name>
      </Expression>
      <MemberName>System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Int32 Length</MemberName>
    </Left>
    <Right xsi:type="EditableConstantExpression">
      <NodeType>Constant</NodeType>
      <Value xsi:type="xsd:int">3</Value>
    </Right>
  </Body>
  <Parameters>
    <EditableExpression xsi:type="EditableParameterExpression">
      <NodeType>Parameter</NodeType>
      <TypeName>System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</TypeName>
      <Name>str</Name>
    </EditableExpression>
  </Parameters>
</EditableLambdaExpression>

【讨论】:

    【解决方案2】:

    很遗憾,System.Linq.Expressions 是不可序列化的,即使在 4.0 中也是如此。如果您必须跨越 appdomain 边界,您将不得不求助于编写自己的表达式树和访问者来从它们生成查询。否则,框表达式树就可以了。

    除此之外,您可能会发现动态 linq 有点适合您的需求。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-09-11
      • 2010-10-14
      • 2016-08-31
      • 2023-03-14
      • 2021-05-17
      • 2020-08-15
      • 2021-07-21
      相关资源
      最近更新 更多