2008-10-17 56 views
7

我有一個接受謂詞<美孚>並返回匹配的項目列表的C#方法...緩存委託結果

public static List<Foo> FindAll(Predicate<Foo> filter) 
{ 
    ... 
} 

過濾器經常是一套通用的一個...

public static class FooPredicates 
{ 
    public static readonly Predicate<Foo> IsEligible = (foo => ...) 
    ... 
} 

...但可能是一個匿名代表。

我現在想有此方法緩存其在ASP.NET緩存結果,與相同的委託所以一再呼籲只返回緩存的結果。爲此,我需要從委託創建一個緩存鍵。 Delegate.GetHashCode()會爲此目的產生明智的結果嗎?我應該看一下其他委員代表嗎?你會完全以另一種方式做這件事嗎?

回答

4

要執行緩存任務,您可以按照其他建議並創建一個詞典<謂詞< Foo>,列表< Foo >>(靜態爲全局或成員字段,否則)緩存結果。在實際執行Predicate < Foo>之前,您需要檢查結果是否已經存在於字典中。

此確定性函數緩存一般的名字叫做記憶化 - 及其真棒:)

自從C#3.0中添加拉姆達的和功能/動作委託的贓物,增加記憶化到C#是很容易的。

韋斯·戴爾擁有great post帶來概念C#與一些偉大的例子。

如果你想讓我告訴你如何做到這一點,讓我知道......否則,韋斯的職位應該足夠。

回答您關於委託哈希代碼的查詢。如果兩個代表是相同的,d1.GetHashCode()應該等於d2.GetHashCode(),但我不是100%的。您可以通過給Memoization一個快速的方法並在您的FindAll方法中添加一個WriteLine來快速檢查它。如果結果不正確,另一個選擇是使用Linq.Expression < Predicate < Foo >>作爲參數。如果表達式不是閉包,那麼做相同事情的表達式應該是相等的。

讓我知道這是怎麼回事,我很想知道關於delegate.Equals的答案。

+0

我已在下面回答以及一些委託測試。等式。我可能會在星期一添加更多,當我嘗試將這些想法用於真實時。 – stevemegson 2008-10-18 13:25:37

2

委託相等性查看調用列表中的每個調用,測試要調用的方法的等同性以及方法的目標。

的方法是一個簡單的片緩存鍵的,但該方法(實例稱之爲上 - 假設的實例方法)的目標可以是不可能的高速緩存中的可序列化的方法。特別是,對於捕獲狀態的匿名函數,它將成爲捕獲該狀態的嵌套類的實例。

如果這一切都是在內存中,只是保持委託本身作爲散列鍵會好起來的 - 雖然它可能意味着哪些客戶會希望被垃圾收集某些對象流連。如果你需要將它序列化到數據庫,它會變得更加複雜。

你能讓你的方法接受一個緩存鍵(例如一個字符串)嗎? (這是假設的內存緩存不足。)

+0

「該方法是一個簡單的緩存鍵」。太糟糕了.Net bizzarely根本不使用它。 (普通)委託的散列碼僅基於調用列表中委託的類型。因此,任何具有4個訂閱者的Action操作委託都具有相同的哈希碼(http://stackoverflow.com/questions/6624151/why-do-2-delegate-instances-return-the-same-hashcode/6624255#6624255 – 2012-12-18 11:40:08

1

除非你確定委託的執行的GetHashCode是確定的,不會導致我不相信任何衝突。

這裏有兩個想法。首先,將謂詞的結果存儲在Predicate/List字典中,使用謂詞作爲鍵,然後將整個結果字典存儲在緩存中的單個鍵下。糟糕的是,如果緩存項丟失,則會丟失所有緩存結果。

另一種方法是創建用於謂詞,信息getKey()的擴展的方法,即使用對象/串字典來存儲和檢索對所有謂詞所有密鑰。你可以用委託索引到字典中,並返回它的密鑰,如果你沒有找到它,就創建一個。通過這種方式,您可以確信,每位代表都能得到正確的密鑰,並且沒有任何碰撞。一個令人反感的將是類型名稱+ Guid。

+0

如果您能夠將代表作爲關鍵字存儲在直接字典中,委託平等(和散列代碼)工作正常。如果您必須以某種方式從內存中取出地圖,代碼平等(和散列代碼)會正常工作。 – 2008-10-17 13:32:00

0

對象的同一個實例總是會返回相同的哈希碼(在.Net中需要GetHashCode())。如果你的謂詞在一個靜態列表中,並且你沒有每次重新定義它們,我不會看到將它們用作鍵的問題。

2

保持緩存結果在字典<謂詞<美孚>列表<美孚>>是尷尬的我,因爲我想要的ASP.NET緩存處理期滿爲我而不是永遠緩存所有的結果,但它是一個,否則好的解決方案我想我最終會用Will的字典<判斷< Foo>,string>來緩存我可以在ASP.NET緩存鍵中使用的字符串。

一些初步測試表明,委託相等並不像其他人說的那樣「正確」,但Delegate.GetHashCode在病理上是無益的。反射器揭示

public override int GetHashCode() 
{ 
    return base.GetType().GetHashCode(); 
} 

所以任何Predicate < Foo>返回相同的結果。

我剩下的問題是平等對匿名代表如何工作。那麼「同一個方法在同一個目標上調用」是什麼意思呢?似乎只要代表在同一​​地點定義,參考資料是平等的。在不同地方定義相同主體的代表不是。

static Predicate<int> Test() 
{ 
    Predicate<int> test = delegate(int i) { return false; }; 
    return test; 
} 

static void Main() 
{ 
    Predicate<int> test1 = Test(); 
    Predicate<int> test2 = Test(); 
    Console.WriteLine(test1.Equals(test2)); // True 

    test1 = delegate(int i) { return false; }; 
    test2 = delegate(int i) { return false; }; 
    Console.WriteLine(test1.Equals(test2)); // False 
} 

這應該是我的需要。具有預定義謂詞的調用將被緩存。通過匿名方法調用FindAll的一個方法的多次調用應該獲得緩存結果。兩個調用FindAll的方法與顯然相同的匿名方法不會共享緩存的結果,但這應該相當少見。