Сложная фильтрация по Value в Dictionary

125
25 декабря 2020, 23:50

Имеется следующий класс:

public class ExportItem
    {
        public Dictionary<string, object> Container { get; set; }
        public ExportItem()
        {
            Container = new Dictionary<string, object>();
        }
    }

Контейнер в данном случае содержит пары ключ (название свойства) - значение этого свойства (числа, строки и перечисления, при необходимости буду делать нужный каст).

Соответственно, имеется список подобных объектов, который нужно отфильтровать по стандартным выражениям (равно, не равно, больше, меньше, больше или равно, меньше или равно, начинается с).

Как поступить в случае с обычным классом, в котором свойства - это свойства, а не ключи словаря, я примерно представляю (хотя так глубоко с лямбда-выражениями раньше работать не приходилось).

var parameter = Expression.Parameter(typeof(People), property);
var member = Expression.Property(parameter, "Id"); //x.Id
var constant = Expression.Constant(3);
var body = Expression.GreaterThanOrEqual(member, constant); //x.Id >= 3
var finalExpression = Expression.Lambda<Func<People, bool>>(body, parameter); //x => x.Id >= 3

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

Пытался использовать что-то вроде:

var parameter = Expression.Parameter(typeof(ExportItem), property);
var member = Expression.Property(parameter, "Container['Id']"); //x.Container['Id']
var constant = Expression.Constant("12");
var body = Expression.GreaterThanOrEqual(member, constant); //x.Container['Id'] >= "12"
var finalExpression = Expression.Lambda<Func<ExportItem, bool>>(body, parameter); //x => x.Container['Id'] >= "12"   

Но предсказуемо ничего не вышло. Названия свойств и их значения, само собой, будут меняться. То есть, нужно что-то вроде настраиваемого:

    return exportItems.Where(c =>
int.Parse(c.Container[conditions[0]].ToString()) >= int.Parse(values[0]) &&
int.Parse(c.Container[conditions[1]].ToString()) != int.Parse(values[1]))
.ToList();

Условий может быть не более двух, типы - int, float, enum, string, ну да это уже отдельный вопрос - если что, сделаю условиями, что-то вроде если число, то больше или равно использовать можно, а если строка - то нет.

UPD: работаем под .NET 3.5

Answer 1

Для обращения по индексу в словаре используется свойство Item. Это стандартное имя свойства индексатора.

Для вызова индексатора в выражениях есть специальная перегрузка, принимающая в дополнение список параметров для индексатора.

В итоге выражение

c.Container[param]

можно собрать так:

var parameter = Expression.Parameter(typeof(ExportItem), property); // c
var container = Expression.Property(parameter, "Container"); //c.Container
var indexer = Expression.Property(container, "Item", Expression.Constant("12")); //c.Container['12']

для более старой версии framework можно воспользоваться тем, что свойства представляют из себя пару методов set_* и get_*. Таким образом для получения значения нужен метод get_Item, который нужно вызвать с переданными параметрами

var parameter = Expression.Parameter(typeof(ExportItem), property); // c
var container = Expression.Property(parameter, "Container"); //c.Container
var getProp = container.Type.GetMethod("get_Item");
var indexer = Expression.Call(container, getProp, Expression.Constant("12")); 
READ ALSO
В матрице A [i, j] m, n поменять местами строки с min и max суммами элементов в строке

В матрице A [i, j] m, n поменять местами строки с min и max суммами элементов в строке

Проблема следующая мы создаем матрицу, задаем размерностьДальше считаем суммы каждой строки

103
Реализация инструмента выделения

Реализация инструмента выделения

Как на wpf реализовать выделение и перемещение выбранной области на канвасе, и если есть несколько вариантов - какой быстрее

104
Проблемы с латиницей при расшифровки FromBase64

Проблемы с латиницей при расшифровки FromBase64

Почему расшифровка не поддерживает латиницу? Пробовал разные методы добавления Encoding не помогло (

140
редактор текста на картинке WPF

редактор текста на картинке WPF

Нужно реализовать функционал редактирования текста на С# как в графических редакторах, например paintУ пользователя возможность перемещать...

124