正确使用 MemoryCache 和泛型?
Proper use of MemoryCache with generics?
我想使用 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)
returns null
如果由 key
标识的缓存条目不存在并且它会在尝试执行时引发 NullReferenceException
(T)null
(具有 T
值类型)
我怎样才能为每个 T
获得类似的行为?
编辑:我删除了 where T : class
,因为此约束阻止了我正在描述的情况。
编辑 2:我添加了一些代码来提供意图
问题是如果值为空,转换可能会失败。所以如果值为 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;
现在根本没有演员!
根据@ericlippart 的回答,这看起来是作为扩展方法实现的好方法,他的回答中有几个问题没有解决:
- 您需要一个缓存策略来将 loadItemFromDb 函数的结果插入到未传递给函数的问题中。
- Eric 的回答中的 Add 方法不存在(带有那个签名)。
由于 MemoryCache
只是抽象 class 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 或更高版本,则可从 NuGet 获得,或者内置于 netstandard2.0
我的 GitHub 存储库 GitHub[=] 中提供了完整的扩展 class,以及 Get 和 TryGetValue 的通用版本,以及 AddOrGetExisting 的许多其他重载19=]
我想使用 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)
returns null
如果由 key
标识的缓存条目不存在并且它会在尝试执行时引发 NullReferenceException
(T)null
(具有 T
值类型)
我怎样才能为每个 T
获得类似的行为?
编辑:我删除了 where T : class
,因为此约束阻止了我正在描述的情况。
编辑 2:我添加了一些代码来提供意图
问题是如果值为空,转换可能会失败。所以如果值为 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;
现在根本没有演员!
根据@ericlippart 的回答,这看起来是作为扩展方法实现的好方法,他的回答中有几个问题没有解决:
- 您需要一个缓存策略来将 loadItemFromDb 函数的结果插入到未传递给函数的问题中。
- Eric 的回答中的 Add 方法不存在(带有那个签名)。
由于 MemoryCache
只是抽象 class 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 或更高版本,则可从 NuGet 获得,或者内置于 netstandard2.0
我的 GitHub 存储库 GitHub[=] 中提供了完整的扩展 class,以及 Get 和 TryGetValue 的通用版本,以及 AddOrGetExisting 的许多其他重载19=]