Вычисление дерева выражения со многими параметрами

Я пытаюсь использовать дерево выражений и объекты выражения Lamdba в .Net 3.5, чтобы позволить мне динамически вычислять логическое выражение, введенное пользователем.

Пока что пользователь может создать дерево выражений, состоящее из BinarayExpressions, где значения И и ИЛИ выражены как ParameterExpressions. Затем я планировал создать LambdaExpression на основе этого дерева, чтобы я мог скомпилировать выражение в делегат, который я мог бы затем вызвать. Проблема, с которой я сталкиваюсь, заключается в том, что я не знаю, сколько входных параметров потребуется пользователю, поэтому, когда я приду к компиляции выражения в делегат, я не знаю, каким методом должна быть сигнатура метода до времени выполнения.

Пока я придумал два возможных решения.

  1. Создайте целую кучу делегатов, таких как Func<bool, bool, bool...>, которые могут принимать столько параметров, сколько, я думаю, может понадобиться пользователю. Это не кажется самым элегантным решением, но я думаю, что оно сработает, пока кто-нибудь не захочет использовать еще один параметр, чем я предусмотрел.
  2. Передайте массив значений и каким-то образом назначьте их моим параметрам с помощью индексатора массива. Я думал об этом, но не могу понять, как это работает.

NB: Это должно быть быстро, поэтому никакого бокса или чего-то подобного.


person Jon Mitchell    schedule 13.09.2009    source источник


Ответы (1)


Я делал точно это раньше, используя метод массива (для Фингвистика, как это бывает). Хитрость Expression.ArrayIndex:

    var arr = Expression.Parameter(typeof(int[]), "arr");
    var body = Expression.ArrayIndex(arr, Expression.Constant(1));
    var expr = Expression.Lambda<Func<int[], int>>(body, arr);
    var func = expr.Compile();

    int[] vals = { 7, 8, 9 };
    int i = func(vals);

Преимущество массивного подхода заключается в том, что вы можете сохранить строго типизированный тип делегата (Func<int[],int> или аналогичный, независимо от количества аргументов. А типизированный Invoke намного быстрее, чем DynamicInvoke.

Если значения не все одного типа - это тоже выполнимо; дайте мне знать, и я добавлю пример.

person Marc Gravell    schedule 13.09.2009
comment
Это работает удовольствие, спасибо Марк. Можете ли вы опубликовать пример, когда типы не совпадают, поскольку я могу предвидеть, что это будет следующим требованием... и мне также интересно узнать, как это делается. - person Jon Mitchell; 15.09.2009