AddOrGetExisting不会将过期时间考虑在内

san*_*erd 5 .net c# memorycache

我正在使用(.NET 4.5)MemoryCache,与SlidingExpiration结合使用.

我注意到方法.AddOrGetExisting()似乎没有考虑到期,而.Get()确实如此.

单元测试:

    [TestMethod]
    public void NonWorking()
    {
        var memCache = new MemoryCache("somekey");
        var cachePolicy = new CacheItemPolicy() { SlidingExpiration = TimeSpan.FromSeconds(1) };

        var cacheEntry = memCache.AddOrGetExisting("key1", "foo", cachePolicy);
        Assert.AreEqual(null, cacheEntry); // OK: AddOrGetExisting returns null, because it wasn't existing yet
        Thread.Sleep(1100);

        // Expecting null, since the existing item for key1 has expired by now.
        // It is, however, still "foo".
        Assert.AreEqual(null, memCache.AddOrGetExisting("key1", "bar", cachePolicy));

        // FYI: afterwards, memCache.Get("key1") still equals "foo"
    }

    [TestMethod]
    public void Working()
    {
        var memCache = new MemoryCache("somekey");
        var cachePolicy = new CacheItemPolicy() { SlidingExpiration = TimeSpan.FromSeconds(1) };

        var cacheEntry = memCache.AddOrGetExisting("key1", "foo", cachePolicy);
        Assert.AreEqual(null, cacheEntry); // OK: AddOrGetExisting returns null, because it wasn't existing yet
        Thread.Sleep(1100);
        Assert.AreEqual(null, memCache.Get("key1"));
    }
Run Code Online (Sandbox Code Playgroud)

题:

这是.AddOrGetExisting()的预期行为吗?

我可以回到.Get()然后,如果为null,.Add().
但是,因此我必须实现自己的锁定以确保线程安全.

CSh*_*pie 3

问题出在AddOrGetExisting的第二次调用上。调用该方法时,它会创建 .net Framework 的 MemoryCacheEntry SourceCode的新实例。在此条目中,它将 Expiration 设置为 UtcNow + 1 Second,使您的 Thread.Sleep 毫无用处。(参见构造函数的这一行)

我不知道为什么它不使用现有条目的策略来确定超时。我猜这一行应该使用existingEntry 而不是entry。也许这是一个错误?

这是框架中产生“不当行为”的代码

existingEntry = _entries[key] as MemoryCacheEntry;
// has it expired?
if (existingEntry != null && /* THERE => */ entry.UtcAbsExp <= DateTime.UtcNow) {
    toBeReleasedEntry = existingEntry;
    toBeReleasedEntry.State = EntryState.RemovingFromCache;
    existingEntry = null;
}
Run Code Online (Sandbox Code Playgroud)

existingEntry 是应该过期的“旧条目”,entry 是具有未过期 UtcAbsExp 值的新条目。