あなたもこれを行うことができます。
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>
を渡すことができますが、これは残念です。
私は次のようなことをします:https://github.com/WiredUK/Wired.Caching/blob/master/Wired.Caching/InMemoryCache.cs#L52。ですから、基本的には、データを(データベースやAPIなどから)キャッシュ関数に渡すための関数を渡しており、必要な場合にのみ呼び出されます。 – DavidG