27

MemoryCache.AddOrGetExisting的行为描述为:

使用指定的键和值以及绝对过期值将缓存条目添加到缓存中。

它返回:

如果存在具有相同key的缓存条目,则现有缓存条目;否则为空。

具有这些语义的方法的目的是什么?这有什么例子?

4

3 回答 3

23

在某些情况下,您只想在不存在匹配条目的情况下创建缓存条目(即,您不想覆盖现有值)。

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-setcompare-and-swap的维基百科条目。)

于 2013-02-05T10:56:36.173 回答
9

LukeH的回答是正确的。因为其他答案表明该方法的语义可以有不同的解释,所以我认为值得指出的是AddOrGetExisting,实际上不会更新现有的缓存条目。

所以这段代码

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

将打印

(空值)
一
一

另一件需要注意的事情:当AddOrGetExisting找到一个现有的缓存条目时,它不会处理传递给调用的 CachePolicy。如果您使用设置昂贵的资源跟踪机制的自定义更改监视器,这可能会出现问题。通常,当缓存条目被驱逐时,缓存系统会调用Dipose()您的 ChangeMonitors。这使您有机会取消注册事件等。但是,当AddOrGetExisting返回现有条目时,您必须自己处理。

于 2014-04-14T17:23:11.220 回答
4

我实际上并没有使用过这个,但我想一个可能的用例是,如果您想用特定键的新条目无条件地更新缓存,并且您想显式处理返回的旧条目。

于 2013-02-05T00:54:52.487 回答