Пользовательские фильтры / запросы? - PullRequest
2 голосов
/ 18 декабря 2009

Я пытаюсь найти способ, позволяющий пользователям моего приложения определять свои собственные запросы или фильтры, которые можно применять к коллекции. Я хочу в конечном итоге предоставить интуитивно понятный пользовательский интерфейс для создания этих фильтров (см. Изображение ниже), но сначала было бы хорошо, если бы пользователю приходилось вводить текстовую строку запроса. Мне также понадобится сериализовать эти пользовательские запросы в строку, чтобы я мог сохранить их вместе с остальной информацией проекта.

Пример пользовательского интерфейса альтернативный текст http://dl.dropbox.com/u/113068/filterUI.jpg

Я ищу тип функциональности, который вы могли бы получить из чего-то вроде SQL-запроса, например числовые условия (меньше, больше чем), строковое условие (содержит, начинается с, заканчивается на) или логическое условие ( правда или ложь). Я также хотел бы иметь возможность группировать условия, используя логическую логику, такую ​​как OR, AND и NOT.

Я начал рисовать, как сделать это с нуля, используя такие классы, как NodeFilter, AbsNodeCondition, NodeStringCondition, NodeConditionOrJoin и т. Д. И т. Д. Но я чувствую, что заново изобретаю колесо, особенно когда есть что-то вроде Linq с которым у меня не было возможности провести много времени.

Могу ли я как-нибудь разрешить пользователю вводить запрос Linq to objects в текстовом поле, а затем программно превращать строку в настоящий запрос Linq, который можно применить к моей коллекции? Или есть какой-то другой способ, которым я мог бы позволить пользователю создавать и сохранять запрос? Мне также понадобится способ сериализации фильтра / запроса в строку, чтобы я мог сохранить его вместе с остальной информацией о программе.

Ответы [ 3 ]

1 голос
/ 18 декабря 2009

Это не обязательно идеальное решение, но проект 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>
0 голосов
/ 30 декабря 2009

System.Linq.Expressions, к сожалению, не сериализуем, даже в 4.0. Вам придется прибегать к написанию собственных деревьев выражений и посетителей, чтобы генерировать из них запросы, если вам нужно пересечь границы домена приложения. В противном случае в окне выражения деревья будут в порядке.

Кроме того, вы можете найти динамическое linq, соответствующее вашим потребностям.

0 голосов
/ 18 декабря 2009

См. мой ответ на аналогичный вопрос , в котором рассказывается, как фильтровать свойство, выбранное из раскрывающегося списка.

...