3

我有一个当前使用 aFunc<T1, T2>作为参数的函数。
我希望它使用Expression<Func<T1, T2>>as 参数,以便在某些情况下可以遍历表达式树。

对于我想使用该函数的每个调用,因此我需要Compile()表达式。为了不必重新编译所有表达式,我想将它们放入字典中。

对我的方法的调用如下所示:

var foo = MyFunc(x => x.Field);

关于Expression用作字典键的以下解决方案是否正确?

static Dictionary<Expression<Func<T1, T2>>, Func<T1, T2>> s_functions = new Dictionary<Expression<Func<T1, T2>>, Func<T1, T2>>();

public T2 MyFunc(Expression<Func<T1, T2>> selectorExpression)
{
    if (!s_functions.ContainsKey(selectorExpression))
    {
        s_functions.Add(selectorExpression, selectorExpression.Compile());
    }

    Func<T1, T2> selector = s_functions[selectorExpression];
}

编辑

从性能的角度来看,什么是解决它的好方法?

4

2 回答 2

4

不幸的是,没有,但问题只会表现为性能错误。

问题是它Expression<TDelegate>没有实现IEquatable<Expression<TDelegate>>,所以字典使用的默认相等比较器只会做引用相等。这意味着相同表达式的不同实例不会比较相同,这将导致本应命中的缓存未命中。另一方面,不同表达式的实例总是比较不同,因此没有逻辑错误。

您可以通过为字典提供自定义相等比较器来解决此问题,但还有一个小问题是必须编写一个 - 这将是一项艰巨的任务。

从好的方面来说,可以编写一个与原始实现具有相同性能错误(但范围缩小)的比较器以换取方便——范围缩小可能解释了您实际遇到的所有或大多数情况要去遇到!例如,您可能想尝试基于ToString()表示的相等性进行比较。只要比较器不产生任何误报,就只有改进的余地。

于 2012-11-13T16:59:54.113 回答
2

用作selectorExpression.ToString()键。它并不完美,因为使用不同参数名称的等效表达式会产生不同的字符串,但这是一种非常简单的方法。

测试:

Expression<Func<int,int>> expr = x => x * x;
MessageBox.Show(expr.ToString()); // ==> "x => (x * x)"
于 2012-11-13T17:45:28.847 回答