Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Пользовательские фильтры / запросы?

Автор вопроса: Eric AnastasОтветов: 2

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

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

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

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

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

  • Ссылка на пример пользовательского интерфейса не работает. Можно ли будет загрузить новую картинку? David 17.03.2017

collectionsfilteringlinq

Ответы

Ответ 1 · рейтинг 1 · Nathan Baulch

Это не обязательно идеальное решение, но проект 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 · Tanveer Badar

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

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы