Search code examples
c#.netexpressionexpression-treesmemoization

Fastest way to memoize expression


I have a function, that transform input Expression to output BlockExpression. So I write this code:

    private static readonly Dictionary<Expression, BlockExpression> MemberMemoizeDictionary = new Dictionary<Expression, BlockExpression>(); 
    private static BlockExpression CreateBody<TProperty>(CustomComparer<T> comparer, Expression<Func<T, TProperty>> member, bool createLabel)
        where TProperty : IComparable<TProperty>, IComparable
    {
        BlockExpression expression;
        if (MemberMemoizeDictionary.TryGetValue(member, out expression))
        {
            return expression;
        }

        MemberExpression memberExpression = (MemberExpression) (member.Body is MemberExpression ? member.Body : ((UnaryExpression)member.Body).Operand);
        BlockExpression result = comparer.CreateCompareTo<TProperty>(memberExpression, createLabel);
        MemberMemoizeDictionary[member] = result;
        return result;
    }

but it's not working.

I was thinking that Expressions are immutable, so I can use them as dictionary keys, but I see it's not true.

What is easiest and fastest way to solve this problem? It's always a single member-expression, with a possible convert due to boxing of value-type properties.


Solution

  • As xantos stated, the expression trees are reference equal, so you cannot use them as dicrionary key. Use the MemberInfo as your key, that will work.

    private static readonly Dictionary<MemberInfo, BlockExpression> MemberMemoizeDictionary = new Dictionary<MemberInfo, BlockExpression>(); 
    private static BlockExpression CreateBody<TProperty>(CustomComparer<T> comparer, Expression<Func<T, TProperty>> member, bool createLabel)
        where TProperty : IComparable<TProperty>, IComparable
    {
        BlockExpression expression;
        MemberExpression memberExpression = (MemberExpression) (member.Body is MemberExpression ? member.Body : ((UnaryExpression)member.Body).Operand);
        if (MemberMemoizeDictionary.TryGetValue(memberExpression.Member, out expression))
        {
            return expression;
        }
    
        BlockExpression result = comparer.CreateCompareTo<TProperty>(memberExpression, createLabel);
        MemberMemoizeDictionary[member] = result;
        return result;
    }
    

    Disclaimer: I didnt check if this code compiles, but i think you get the point :)