我有一个存储库装饰器。该装饰器负责装饰存储库的缓存。在我的这个装饰器的大多数函数中,我只返回缓存的结果(如果存在)或者在装饰的存储库上调用方法,并将此结果存储在缓存中(如果尚未存在于此缓存中)。我这样做是安全的。
但是我想在一个方法中执行这个获取缓存锁定的例程,并使用lambda表达式调用它。
我获取缓存结果或加载缓存的方法:
private X CallCachedAndLocked<X>(string methodCacheKey, xxx methodToCallWithParameter)
{
var cacheKey = GetCacheKey(methodCacheKey);
X obj = (X)Cache.Get(cacheKey);
if (obj == null)
{
lock (getLastDrawResult_lock)
{
if (obj == null)
{
obj = methodToCallWithParameter;
if (obj != null)
{
Cache.Add(cacheKey,
obj,
null,
NextExpiration,
System.Web.Caching.Cache.NoSlidingExpiration,
CacheItemPriority.AboveNormal, null);
}
}
}
}
}
电话示例:
public T GetDraw(int id)
{
return CallCachedAndLocked<T>(() => _decoratedRepository.GetDraw(id));
}
public IEnumerable<T> GetDraws(DateTime from)
{
return CallCachedAndLocked<T>(() => _decoratedRepository.GetDraws(GetDraws));
}
答案 0 :(得分:0)
我建议使用.Net中的Lazy类,它看起来像是您需要的匹配项:
var lazyCall = new Lazy<T>(() => new T());
并且在访问值
时 lazyCall.Value // launches evaluation of the lambda expression
您可以将任何lambda设置为Lazy的评估代码,因此只要您在存取访问器的范围内,就可以使用它们来运行初始化代码:
var c = MyCache.Get[key]();
if (c == null)
{
c = methodToCallWithParameter(key);
MyCache.Add(key, c);
}
return c;
或多或少等同于:
c = new Lazy<cType>(() => methodToCallWithParameter(key));
return c;
然后在调用代码中使用c.Value
。
答案 1 :(得分:0)
我终于找到了一个带有反射的解决方案。没有它,我没有看到解决方案:
public static DateTime GetCachedMethod(int nbMonth, NonDecoratedClass repo)
{
var methodCacheKey = "Test";
DateTime obj = new DateTime();
if (!cache.ContainsKey(methodCacheKey))
{
lock (zeLock)
{
if (!cache.ContainsKey(methodCacheKey))
{
obj = repo.GetDateTimeAndMonth(nbMonth);
if (obj != null)
{
cache.Add(methodCacheKey, obj);
}
}
}
}
else
{
obj = (DateTime)cache[methodCacheKey];
}
return obj;
}
if (!cache.ContainsKey(methodCacheKey))
{
lock (zeLock)
{
if (!cache.ContainsKey(methodCacheKey))
{
obj = repo.GetDateTimeAndMonth(nbMonth);
if (obj != null)
{
cache.Add(methodCacheKey, obj);
}
}
}
}
else
{
obj = (DateTime)cache[methodCacheKey];
}
return obj;
}
答案 2 :(得分:-1)
您可以使用以下行的扩展方法轻松完成此操作:
private static readonly _lock = new object();
public static void Lock(Action action)
{
// Lock.
lock (_lock) action();
}
public static T Lock<T>(Func<T> func)
{
// Lock.
lock (_lock) return func();
}
但是,你真的不应该这样做;您正在为所有内容共享相同的锁定,这只会导致争用。
您希望锁定尽可能精细,以便在锁定时不会占用其他等待的线程。在这里使用共享锁是精细的。