Ленивая оценка выражений linq - PullRequest
1 голос
/ 05 октября 2010

Я пытаюсь построить оценщик выражений с помощью выражений Linq.Я пытаюсь сделать так, чтобы все аргументы функции вычислялись лениво, но не могли до них добраться.

Я пишу здесь в psuedo, но на самом деле это выражения linq.

Пример выражения:

Func1(Func2(10) + 1, Func3(10))

Обновление

Expression.Call(Func1,
    Expression.Add(
        Expression.Call(Func2, Expression.Constant(10)),
        Expression.Constant(1))
    Expression.Call(Func3, Expression.Constant(10))
)

Я хочу, чтобы аргументы Func1 оценивались во время вызова, то есть я хочу, чтобы аргументы оценивались лениво.Это возможно при переносе выражений аргумента в лямбда-выражение, но если я сделаю это, двоичное выражение Func2 (10) + 1 не будет выполнено, потому что нельзя добавить лямбда-выражение в константное выражение.

Фактический код функциибудет выглядеть так:

  int Func1(Func<int> arg1, Func<int> arg2)
  {
  }

arg1 при запуске будет вычислять "Func2 (10) + 1"
arg2, когда запуск будет оценивать "Func3 (10)"

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

Возможно ли это сделать?

1 Ответ

3 голосов
/ 05 октября 2010

Для начала, я думаю, было бы полезно сначала обсудить проблему без использования деревьев выражений. Вы сказали, что эту функцию вы хотите вызвать:

int Func1(Func<int> arg1, Func<int> arg2)
{
}

А вы хотите выяснить, как реализовать следующее с помощью деревьев выражений?

Func1(() => Func2(10) + 1, () => Func3(10));

Это правильно до сих пор? Если это все правда, то рассмотрим этот класс:

class Program
{
    public static void Main(string[] args)
    {
        Console.WriteLine(Func1(() => Func2(10) + 1, () => Func3(10)));            

        var arg1 = Expression.Add(Expression.Call(typeof(Program), "Func2", Type.EmptyTypes, Expression.Constant(10)), Expression.Constant(1));
        var arg2 = Expression.Call(typeof(Program), "Func3", Type.EmptyTypes, Expression.Constant(10));
        var callFunc1 = Expression.Call(typeof(Program), "Func1", Type.EmptyTypes, Expression.Lambda<Func<int>>(arg1), Expression.Lambda<Func<int>>(arg2));
        var tester = Expression.Lambda<Func<int>>(callFunc1);
        int result = tester.Compile()();

        Console.WriteLine(result);
    }

    static int Func1(Func<int> arg1, Func<int> arg2)
    {
        return arg1() + arg2();
    }

    static int Func2(int arg)
    {
        return arg;
    }

    static int Func3(int arg)
    {
        return 2 * arg;
    }
}

Будет распечатано 31 оба раза: (10 + 1) + (10 * 2). Первый вызывает его напрямую, второй использует деревья выражений.

...