web-dev-qa-db-ja.com

MemoryCache.AddOrGetExistingとは何ですか?

MemoryCache.AddOrGetExisting の動作は次のように記述されます。

指定されたキーと値、および絶対有効期限値を使用して、キャッシュエントリをキャッシュに追加します。

そしてそれが戻ること:

同じキーを持つキャッシュエントリが存在する場合、既存のキャッシュエントリ。それ以外の場合はnull。

これらのセマンティクスを持つメソッドの目的は何ですか?この例は何ですか?

25
Dave Hillier

一致するエントリがまだ存在しない場合(つまり、既存の値を上書きしたくない場合)にのみキャッシュエントリを作成したい場合がよくあります。

AddOrGetExisting これをアトミックに行うことができます。 AddOrGetExisting がないと、アトミックでスレッドセーフな方法でget-test-setを実行することは不可能です。例えば:

 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")

Interlocked.CompareExchange メソッド。これにより、変数レベルでより洗練された同等物が有効になり、 test-and-set および compare-and-swap のウィキペディアエントリも有効になります。 )

23
LukeH

LukeHの答えは正しいです。他の回答は、メソッドのセマンティクスが異なる方法で解釈される可能性があることを示しているため、AddOrGetExistingは実際にはnot既存のキャッシュエントリを更新することを指摘する価値があると思います。

したがって、このコード

 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())); 

印刷します

(null)
 one 
 one 

注意すべきもう1つのこと:AddOrGetExistingが既存のキャッシュエントリを見つけると、not呼び出しに渡されたCachePolicyを破棄します。これは、高価なリソース追跡メカニズムを設定するカスタム変更モニターを使用する場合に問題になる可能性があります。通常、キャッシュエントリが削除されると、キャッシュシステムはChangeMonitorでDipose()を呼び出します。これにより、イベントなどの登録を解除することができます。ただし、AddOrGetExistingが既存のエントリを返す場合は、自分で処理する必要があります。

8
Sven Künzler

私は実際にこれを使用していませんが、考えられるユースケースの1つは、特定のキーの新しいエントリでキャッシュを無条件に更新し、返された古いエントリを明示的に破棄する場合です。