是否有更有效的方法来检查缓存数据是否退出,是否确实获得了它,以及它是否未调用api /数据库然后缓存它?我一遍又一遍地执行这样的代码似乎效率很低。
List<Map> maps = new List<Map>();
List<Playlist> playlists = new List<Playlist>();
if (SingletonCacheManager.Instance.Get<List<Map>>("Maps") != null)
{
maps = SingletonCacheManager.Instance.Get<ListMap>>("Maps");
}
else
{
maps = _mapRepository.FindBy(x => x.Active).ToList();
SingletonCacheManager.Instance.Add<List<Map>>(maps, "Maps", 20);
}
if (SingletonCacheManager.Instance.Get<List<Playlist>>("Playlists") != null)
{
playlists = SingletonCacheManager.Instance.Get<List<Playlist>>("Playlists");
}
else
{
var p = await _apiService.GetPlaylists();
playlists = p.ToList();
SingletonCacheManager.Instance.Add<List<Playlist>>(playlists, "Playlists", 20);
}
这样的事情是可能的:
List<Map> maps = this.CacheHelper.GetCachedItems<Map>(key, lengthoftime);
然后GetCachedItems将检查缓存的项目并相应地进行检索。这似乎是可行的,但是当缓存的项目不存在时,我必须从api /数据库中检索项目,我不知道它是否可以通用。
唯一的解决方案是传入类型的switch语句?
switch(<T>type)
{
case<Map>:
return _mapRepository.FindBy(x => x.Active);
case<Playlist>:
return await _apiService.GetPlaylists();
}
感谢您的帮助。
答案 0 :(得分:1)
我的解决方案是传递获取您需要缓存的数据的函数作为lambda表达式。这样,缓存方法可以检查缓存并仅在需要时调用委托。例如:
public T Get<T>(string key, Func<T> getItemDelegate, int duration) where T : class
{
var cache = GetCache();
var item = SingletonCacheManager.Instance.Get<ListMap>>(key) as T;
if (item != null) return item;
item = getItemDelegate();
SingletonCacheManager.Instance.Add<T>(item, key, duration);
return item;
}
现在你可以像这样调用Get函数:
var maps = Get<List<Map>>(
"Maps",
() => _mapRepository.FindBy(x => x.Active).ToList(),
20);
答案 1 :(得分:1)
你也可以这样做:
public interface ICacheManager
{
IList<T> Get<T>(string name);
void Add<T>(IList<T> data, string Id, int lifeTime);
}
public class CacheHelper
{
private readonly Dictionary<Tuple<Type, string>, Func<IEnumerable<object>>> dataRetrievalFuncs;
private readonly ICacheManager cacheManager;
public CacheHelper(ICacheManager cacheManager)
{
this.cacheManager = cacheManager;
dataRetrievalFuncs = new Dictionary<Tuple<Type, string>, Func<IEnumerable<object>>>();
}
public void Register<T>(string name, Func<IEnumerable<T>> selector) where T : class
{
dataRetrievalFuncs[new Tuple<Type, string>(typeof(T), name)] =
() => (IEnumerable<object>)selector();
}
public IList<T> GetCachedItems<T>(string name, int lifeTime = 20)
where T : class
{
var data = cacheManager?.Get<T>(name);
if (data == null)
{
data = (dataRetrievalFuncs[new Tuple<Type, string>(
typeof(T), name)]() as IEnumerable<T>)
.ToList();
cacheManager.Add(data, name, lifeTime);
}
return data;
}
}
现在,您需要为每种类型注册数据检索功能,然后只需使用帮助程序:
//Setting up the helper
CacheHelper helper = new CacheHelper(SingletonCacheManager.Instance);
helper.Register("Maps", () => _mapRepository.FindBy(x => x.Active));
helper.Register( "PlayLists", ... );
//Retrieving data (where it comes from is not your concern)
helper.GetCachedItems<Map>("Maps");
helper.GetCachedItems<PlayList>("Playlists");
正如下面的评论所指出的,此解决方案可能会对用于检索数据的依赖项(_mapRepository
)的生命周期产生问题。解决方法是使用相同的解决方案,但在数据检索时显式传递依赖:
public class CacheHelper
{
private readonly Dictionary<Tuple<Type, string>, Func<object, IEnumerable<object>>> dataRetrievalFuncs;
private readonly ICacheManager cacheManager;
public CacheHelper(ICacheManager cacheManager)
{
this.cacheManager = cacheManager;
dataRetrievalFuncs = new Dictionary<Tuple<Type, string>, Func<object, IEnumerable<object>>>();
}
public void Register<TEntity, TProvider>(string name, Func<TProvider, IEnumerable<TEntity>> selector)
where TEntity : class
where TProvider: class
{
dataRetrievalFuncs[new Tuple<Type, string>(typeof(TEntity), name)] =
provider => (IEnumerable<object>)selector((TProvider)provider)
}
public IList<TEntity> GetCachedItems<TEntity>(string name, object provider, int lifeTime = 20)
where TEntity : class
{
var data = cacheManager?.Get<TEntity>(name);
if (data == null)
{
data = (dataRetrievalFuncs[new Tuple<Type, string>(
typeof(TEntity), name)](provider) as IEnumerable<TEntity>)
.ToList();
cacheManager?.Add(data, name, lifeTime);
}
return data;
}
}
现在使用会略有不同:
//Setting up the helper
CacheHelper helper = new CacheHelper(SingletonCacheManager.Instance);
helper.Register("Maps", (MapRepository r) => r.FindBy(x => x.Active));
//Retrieving data (where it comes from is not your concern)
helper.GetCachedItems<Map>("Maps", _mapRepository);
请注意,最后一个解决方案不是类型安全的。您可以将错误输入的provider
传递给GetCachedItems<T>
,这是不幸的。
答案 2 :(得分:0)
为什么不为地图和播放列表使用不同的缓存?如果你这样做,你可以编写一个基本的抽象类,并且只覆盖从每个抽取api中读取数据的方法。