我希望使用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)
标识的缓存条目不存在,则{p> null
会返回key
,并且会在NullReferenceException
尝试(T)null
时引发T
T
值类型)
我怎样才能为每个where T : class
获得类似的行为?
编辑:我删除了@Dao
public abstract class EntityDao implements Base {
@Override
@Query("SELECT * FROM " + Entity.TABLE_NAME)
public abstract Flowable<List<Entity>> getEntities();
}
interface Base {
Flowable<List<Entity>> getEntities();
}
,因为此约束阻止了我正在描述的情况。
编辑2:我添加一些代码来提供意图
答案 0 :(得分:4)
问题是如果值为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的FYI,您可以将其收紧一点:
if (cachedItem is T t)
return t;
现在根本没有演员阵容!
答案 1 :(得分:0)
根据@ ericlippart的回答,这看起来像是一种很好的方法来实现作为扩展方法,并且在他的回答中没有解决几个问题:
由于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的许多其他重载。