我有一个存储库装饰器。这个decorator负责缓存已装饰的存储库。在这个装饰器的大多数函数中,如果存在,我只返回缓存的结果,或者调用装饰的存储库上的方法,如果还没有在缓存中,则将此结果存储在缓存中。我这样做是为了安全。
但我想做这个获取缓存锁的例程。。。在单个方法中,并用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));
}
我建议使用.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;
然后在呼叫码中使用CCD_ 3。
我终于找到了反射的解决方案。我看不到没有它的解决方案:
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;
}
您可以使用以下扩展方法轻松完成此操作:
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();
}
然而,你真的不应该这样做;您正在为所有内容共享相同的锁,这只会导致争用。
您希望您的锁尽可能细粒度,以免在锁定时阻塞其他等待线程。在这里使用共享锁不是细粒度的。