【问题标题】:Proper use of MemoryCache with generics?使用泛型正确使用 MemoryCache?
【发布时间】:2018-03-15 21:20:00
【问题描述】:

我希望使用System.Runtime.Caching.MemoryCache,但我想知道如何将它与泛型一起使用。

在以下示例中,如果T 是值类型,我将遇到麻烦。

public T GetItem<T>(string key, Func<T> loadItemFromDb)
{
    var cachedItem = (T) memoryCache.Get(key);
    if(cachedItem != null)
       return cachedItem;

    // call db
    //put result in cache
    // return result
}

MemoryCache.Get(string key) 如果key 标识的缓存条目不存在,则返回null,它会在尝试执行(T)null 时引发NullReferenceException(使用T 值类型)

我怎样才能为每个 T 获得类似的行为?

编辑:我删除了where T : class,因为这个约束阻止了我所描述的情况。

编辑 2:我添加了一些代码来提供意图

【问题讨论】:

  • var item = memoryCache.Get(key) as T;
  • @RonBeyer 我认为as 仅供参考和可空类型?
  • 你的where T : class 使T 可以为空,它不能是值类型,class 只是一个引用类型。
  • 那你需要检查类型:var item = memoryCache.Get(key); if (item is T) return (T)item; else return default(T); 或者类似的东西。
  • 您问“我该如何解决这个问题?”不说你想发生什么。我假设你不想可怕地崩溃,但你还没有说出你想要发生的事情。你打电话给GetItem&lt;int&gt;("foo") 并且key foo 不存在,然后......会发生什么?

标签: c# generics value-type reference-type memorycache


【解决方案1】:

问题是如果值为 null,则转换可能会失败。所以如果值为 null,则不要强制转换

public T GetItem<T>(string key, Func<T> loadItemFromDb)
{
    object cachedItem = memoryCache.Get(key);
    if (cachedItem is T)
       return (T)cachedItem;
    T item = loadItemFromDb();
    memoryCache.Add(key, item, somePolicy);
    return item;
}

这里的值类型没有问题;如果 T 是值类型,并且 cachedItem 不是装箱的 T,那么我们永远不会将 cachedItem 转换为 T

在 C# 7 中仅供参考,您可以将其收紧一点:

    if (cachedItem is T t)
       return t;

现在根本没有演员表!

【讨论】:

    【解决方案2】:

    根据@ericlippart 的回答,这看起来是作为扩展方法实现的好方法,但他的回答中没有解决几个问题:

    1. 您需要一个缓存策略来将 loadItemFromDb 函数的结果插入到未传递给函数的问题中。
    2. Eric 的答案中的 Add 方法不存在(带有该签名)。

    由于MemoryCache 只是抽象类ObjectCache 的一个实现,它不使用任何MemoryCache 特定功能,所以我基于ObjectCache

    AddOrGetExisting 方法在ObjectCache 上的通用版本的完整实现:​​

        public static T AddOrGetExisting<T>(ObjectCache cache, string key, Func<(T item, CacheItemPolicy policy)> addFunc)
        {
            object cachedItem = cache.Get(key);
            if (cachedItem is T t)
                return t;
            (T item, CacheItemPolicy policy) = addFunc();
            cache.Add(key, item, policy);
            return item;
        }
    

    请注意,这使用了提到的 C# 7 增强功能以​​及 System.ValueTuple,如果使用 net461 或更高版本或内置于 netstandard2.0,则可以从 NuGet 获得该功能

    我的 GitHub 存储库 CZEMacLeod/ObjectCacheExtensions 中提供了完整的扩展类,以及 Get 和 TryGetValue 的通用版本,以及 AddOrGetExisting 的许多其他重载

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-16
      • 2013-04-29
      • 1970-01-01
      • 1970-01-01
      • 2014-02-11
      • 1970-01-01
      • 2019-08-26
      • 2022-01-19
      相关资源
      最近更新 更多