2009-09-22 83 views
3

我需要获取一些作为lambda表达式传递给某些方法的信息。基本上,这是一种将信息添加到数据库查询的方法。一个简单的例子是:缓存编译的lambda表达式

companyData.GetAll(
    where => "SomeField = @SOMEFIELD", 
    order => "Id", 
    SOMEFIELD => new Parameter {DbType = DbType.String, Value = "some value"} 
) 

它的工作非常好,除了事实上,我需要调用LambdaExpression.Compile获取参数对象,其中有一个很大的性能比较的影响。

要获得更快的结果,我来到这个天真的缓存测试:

class ExpressionCache<T,U> 
{ 

    private static ExpressionCache<T, U> instance; 
    public static ExpressionCache<T, U> Instance 
    { 
     get 
     { 
      if (instance == null) { 
       instance = new ExpressionCache<T, U>(); 
      } 
      return instance; 
     } 
    } 

    private ExpressionCache() { } 

    private Dictionary<string, Func<T, U>> cache = new Dictionary<string, Func<T, U>>(); 

    public Func<T, U> Get(Expression<Func<T, U>> expression) 
    { 
     string key = expression.Body.ToString(); 
     Func<T,U> func; 
     if (cache.TryGetValue(key, out func)) { 
      return func; 
     } 
     func = expression.Compile(); 
     cache.Add(key, func); 
     return func; 
    } 
} 

该类作出了巨大的差异:约35000毫秒的10000次迭代约700

现在来这个问题:我将使用表达式体作为字典的关键点遇到什么样的问题?

回答

9

我不清楚为什么你需要表达式树,如果你把它们编译给代表。为什么不只是使用委托来开始并让编译器将lambda表达式转换为委托而不是表达式树?

至于使用字符串的主体 - 你可能会遇到奇怪的情况,你使用不同的类型,但使用相同的属性名称。但是,鉴于您已经将这些类型用作泛型类型参数,这可能不是问题...我应该认为它可以工作,但我想发誓

哦,你的单身高速缓存不是线程安全的。我建议你在静态初始化器中初始化instance变量。这导致更简单的代码以及它更安全...

private static readonly ExpressionCache<T, U> instance 
    = new ExpressionCache<T, U>(); 
public static ExpressionCache<T, U> Instance { get { return instance; } } 
+2

+1“哦,你的单例缓存不是线程安全的。” – 2009-09-22 18:42:40

+0

@Dan:我想要多一点帮助...... – 2009-09-22 18:48:21

+0

@Jon:我知道不是线程安全的。这只是一个测试。感谢您提供“公正的代表”的想法。我想我太喜欢这个lambda的东西了。 – Fernando 2009-09-22 18:53:36

9

Lambda表达式可以创建闭包。当发生这种情况时,表达式主体不包含进入结果代码的所有内容。您可能会丢失包含的潜在重要局部变量。

+2

任何解决方案,这仍然存档缓存? – TobiHeidi 2012-07-08 12:12:39