记忆表达的最快方法

时间:2015-05-01 19:10:04

标签: c# .net expression expression-trees memoization

我有一个函数,它将输入Expression转换为输出BlockExpression。所以我写了这段代码:

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

但它不起作用。

我当时认为Expressions是不可变的,所以我可以将它们用作字典键,但我发现它不是真的。

解决此问题的最简单,最快捷的方法是什么?它始终是一个单独的成员表达式,由于值类型属性的装箱而可能convert

2 个答案:

答案 0 :(得分:2)

  

我认为表达式是不可变的

但请注意,每次都会重新生成表达式!

public static Expression Exp = null;

public static void Foo(Expression<Func<bool>> exp)
{
    if (Exp == null)
    {
        Exp = exp;
    }
    else
    {
        Console.WriteLine(object.ReferenceEquals(Exp, exp));
    }

}

for (int i = 0; i < 2; i++)
{
    Foo(() => true);
}

写入

False

可悲的是,“文字”Expression没有被C#编译器“拦截”。它甚至写在MSDN的某个地方。

答案 1 :(得分:1)

正如xantos所说,表达式树是引用相等的,所以你不能将它们用作dicrionary键。使用MemberInfo作为您的密钥,这将起作用。

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

免责声明:我没有检查此代码是否编译,但我认为你明白了这一点:)