Search code examples
c#linq-expressions

Can I reuse one Expression object for multiple lambdas building?


I want to reuse Expression instances for another Expression building like in the code below. Is it safe? Are there any pitfalls with it?

using System.Linq.Expressions;

class Program
{
    static void Main()
    {
        ParameterExpression x = Expression.Parameter(typeof(int), "x");
        ParameterExpression y = Expression.Parameter(typeof(int), "y");
        // Reuse x and y parameter expressions
        BinaryExpression sum = Expression.Add(x, y);
        BinaryExpression mutiply = Expression.Multiply(x, y);

        // Reuse multiply and sum expressions
        BinaryExpression foo = Expression.Subtract(mutiply, sum); // xy - (x + y)

        Func<int, int, int> sumFunc = Expression.Lambda<Func<int, int, int>>(sum, x, y).Compile();
        Func<int, int, int> multiplyFunc = Expression.Lambda<Func<int, int, int>>(mutiply, x, y).Compile();
        Func<int, int, int> fooFunc = Expression.Lambda<Func<int, int, int>>(foo, x, y).Compile();
        
        Console.WriteLine(sumFunc(3, 2));
        Console.WriteLine(multiplyFunc(3, 2));
        Console.WriteLine(fooFunc(3, 2));
    }
}

Solution

  • You can safely reuse expressions.

    Expression trees are immutable, so you don't need to worry about whoever using sum modifying the LHS and RHS expressions, causing whoever is using multiply to also (unexpectedly) see the change. Of course, if you deliberately put something mutable in a node (e.g. a List<T>), something like the above could happen. But that isn't really Expression's problem.

    Expression is a reference type, so the only difference that reusing vs not reusing is going to make, is that some tree nodes will have the same references to the child node. For example, in your code, object.ReferenceEquals(sum.Left, multiply.Left) would be true. If you didn't reuse x, it would be false. That said, it is very hard to imagine any use case of expression trees that depend on whether two nodes are the same reference. Most APIs that consume expression trees just look at the types of the nodes, and the values in them.