2009-09-22 84 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