2010-10-05 3 views
1

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

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

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

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

Update

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

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

Реальная функция код будет выглядеть следующим образом:

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

arg1 при запуске будет оценивать "func2 (10) + 1"
арг2 при запуске будет оценивать "FUNC3 (10)"

Поэтому я могу выбрать, хочу ли я анализировать аргумент или нет, чтобы получить ленивый эффект.

Можно ли выполнить?

+0

Я думаю, что реальный код дерева выражений будет улучшением для нас над вашим псевдокодом. –

+0

@Kirk: Хорошо, я отредактирую свое сообщение. – Marcus

+0

Благодарим за редактирование. Но я смущен, почему вы думаете, что это уже не * лениво оценивается? Выражение 'Func2 (10) + 1' не будет оцениваться до тех пор, пока не вызывается' Func1'. Что мне не хватает? –

ответ

3

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

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). Первый вызывает его напрямую, второй - с использованием деревьев выражений.

+0

Да, это правильно. Я хочу, чтобы все мои функции действовали таким образом. – Marcus

+0

Спасибо, это выглядит интересно, посмотрим на это завтра. – Marcus

+0

Деревья выражений неизменяемы.Итак, следующим шагом будет создание посетителя дерева выражений, который копирует любые узлы не-функциональных вызовов в новое дерево и преобразует любые узлы вызова функций в вызовы лямбда-выражений, которые вызывают эти узлы вызова функций. Правильно? – StriplingWarrior