views:

23

answers:

1

Hi, Im trying to build a expression evaluator with Linq expressions. Im trying to make It so that all function arguments are lazy evaluated but can't quite get there.

I'm writing in psuedo here but the real thing is linq expressions.

Example expression:

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))
)

I want the arguments to Func1 to be evaluated at invoke-time that is I want the arguments to be lazy evaluated. It's doable when wrapping the argument expressions inside a lambda expression but if I do that the binary expression Func2(10) + 1 will fail because one can't add a lambda to a constant expression.

The actual function code will look like this:

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

arg1 when run will evaluate "Func2(10) + 1"
arg2 when run will evaluate "Func3(10)"

So here I can choose if I want to evalute the argument or not, to get the lazy effect.

Is this possible to accomplish?

+2  A: 

To begin, I think it would be helpful to first discuss the problem without the use of expression trees. You said that this is the function you want to call:

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

And you want to figure out how to implement the following using expression trees?

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

Is this correct so far? If that is all true, then consider this class:

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;
    }
}

It will print out 31 both times: (10 + 1) + (10 * 2). The first is invoking it directly, the second using expression trees.

Kirk Woll
Yeah, that is correct. I want all of my functions to act this way.
Marcus
Thanks, this looks interesting, will look at it more tomorrow.
Marcus
Expression trees are immutable. So the next step would be to create an expression tree visitor that copies any non-function-call nodes into a new tree, and converts any function-call nodes into calls to lambda expressions which invoke those function-call nodes. Right?
StriplingWarrior