2013-02-05 24 views
22

Zachowanie MemoryCache.AddOrGetExisting jest opisany jako:Do czego służy MemoryCache.AddOrGetExisting?

Dodaje wpis do pamięci podręcznej cache przy użyciu określonego klucza i wartości i bezwzględną wartość ważności.

I że zwraca:

Jeśli wpis cache z tym samym kluczem istnieje, istniejący wpis pamięci podręcznej; w przeciwnym razie wartość null.

Jaki jest cel metody z tymi semantykami? Jaki jest tego przykład?

+2

Przykład użycia w połączeniu z Lazy http://stackoverflow.com/a/15894928/1575281 –

+3

Dobrze się cieszę, że nie jestem jedyny ... spodziewałem się uzyskać wartość, którą właśnie przekazałem powrót do pierwszego połączenia, nie ma wartości null –

Odpowiedz

18

Często zdarza się, że chcesz utworzyć pozycję pamięci podręcznej tylko wtedy, gdy pasujący wpis nie istnieje (to znaczy, że nie chcesz zastąpić istniejącej wartości).

AddOrGetExisting pozwala to zrobić atomowo. Bez AddOrGetExisting nie byłoby możliwe wykonanie zestawu get-test w sposób niepodzielny na wątki. Na przykład:

Thread 1       Thread 2 
--------       -------- 

// check whether there's an existing entry for "foo" 
// the call returns null because there's no match 
Get("foo") 

            // check whether there's an existing entry for "foo" 
            // the call returns null because there's no match 
            Get("foo") 

// set value for key "foo" 
// assumes, rightly, that there's no existing entry 
Set("foo", "first thread rulez") 

            // set value for key "foo" 
            // assumes, wrongly, that there's no existing entry 
            // overwrites the value just set by thread 1 
            Set("foo", "second thread rulez") 

(Patrz również metodę Interlocked.CompareExchange, który umożliwia bardziej wyrafinowany odpowiednik na poziomie zmiennej, a także wpisy Wikipedię test-and-set i compare-and-swap).

+0

Niezłe wyjaśnienie. Ale dlaczego mielibyśmy użyć właśnie 'Add'? Czy nie lepiej zawsze używać 'AddOrGetExisting'? – Joze

+2

Nie byłoby to całkowicie "niemożliwe", ponieważ można zawijać wywołania Get/Set w instrukcji blokującej. – rymdsmurf

4

Tak naprawdę nie używałem tego, ale myślę, że jednym z możliwych przypadków użycia jest, jeśli chcesz bezwarunkowo zaktualizować pamięć podręczną o nowy wpis dla określonego klucza i chcesz jawnie pozbyć się starego zwracanego hasła.

+0

+1 dla "kiedy chcesz jawnie pozbyć się starego wpisu" – Seph

+2

Ma to sens, ale zastanawiam się, czy to prawda ... nikt nie wydaje się tłumaczyć, dlaczego po raz pierwszy zwraca zero dzwonisz do AddOrGetExisting. –

4

odpowiedź LukeH jest prawidłowe. Ponieważ inne odpowiedzi wskazują, że semantykę tej metody można interpretować inaczej, uważam, że warto zauważyć, że AddOrGetExisting faktycznie będzie aktualizować istniejące wpisy pamięci podręcznej.

Więc ten kod

 
Console.WriteLine(MemoryCache.Default.AddOrGetExisting("test", "one", new CacheItemPolicy()) ?? "(null)"); 
Console.WriteLine(MemoryCache.Default.AddOrGetExisting("test", "two", new CacheItemPolicy())); 
Console.WriteLine(MemoryCache.Default.AddOrGetExisting("test", "three", new CacheItemPolicy())); 

wypisze

 
(null) 
one 
one 

Inną rzeczą, aby mieć świadomość: Kiedy AddOrGetExisting znajdzie istniejący wpis pamięci podręcznej, to będzie nie dysponowania CachePolicy przekazywane do połączenie. Może to być problematyczne, jeśli używasz niestandardowych monitorów zmian, które konfigurują drogie mechanizmy śledzenia zasobów. Zwykle, gdy wpis w pamięci podręcznej jest eksmitowany, system pamięci podręcznej wywołuje Dipose() na swoim ChangeMonitors. Daje to możliwość wyrejestrowania wydarzeń i tym podobnych. Kiedy AddOrGetExisting zwraca istniejący wpis, sam musisz to zrobić.

+0

Należy również zwrócić uwagę na: Metody 'Add' lub wywoływanie' AddOrGetExisting' pod maską. – springy76