C# - 缓存加载缓存
我有一个存储库修饰器。这个装饰器负责装饰存储库的缓存。在这个装饰器的大部分函数中,我只是返回缓存的结果(如果存在),或者调用装饰存储库上的方法,并将此结果存储在缓存中(如果尚未存在于此缓存中)。我做那个安全。C# - 缓存加载缓存
但我想做这个例程获取缓存锁,...在一个单一的方法,并调用它与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作为懒惰的评估代码,所以只要你是在一个范围在您存取存在的时候,你可以用它们来运行初始化代码:
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
。
我不认为它会做的伎俩在这里有两个原因: - 我必须传递一些参数并调用我的存储库上的方法 - 它没有缓存 – user2003035 2014-09-29 12:59:19
然后只需在Lazy声明期间调用该方法
我不需要将密钥传递给我的方法来调用,以及如何在我的常规函数中定义参数methodToCallWithParameter? – user2003035 2014-09-29 13:28:28
您可以轻松地沿线的扩展方法做到这一点:
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();
}
但是,你真的不应该做到这一点;你会分享相同的锁定所有内容,这只会导致争用。
您希望您的锁尽可能细化,以便锁定时不锁定其他等待线程。在这里使用共享锁是非常精细的。
你说得对,我会用锁的字典。但它不能解决我的问题,因为我需要有多次我的方法调用一次它是一个int,另一次是两个日期,... – user2003035 2014-09-29 13:04:24
这就是我想要做的点,你'有一本关于锁的字典(这里的关键是什么,'Func'?没有任何作用,因为它是一个参考)。您希望保留与调用“GetDraw”,“GetDraws”等的锁定代码,您可以在其中锁定其他锁以实现所需的粒度。 – casperOne 2014-09-29 18:38:49
我终于找到了解决方案与反思。我没有看到没有它的解决方案: 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;
}
你想传递的关键和lambda,或lambda只? – 2014-09-29 12:42:19
我不认为你需要这里的双重检查锁。 obj是一个局部变量,它在堆栈中,不会被共享等等。不是吗? – ziya 2014-09-29 12:55:36
我不完全明白这个问题。底层存储库调用是否需要同步发生? – ziya 2014-09-29 12:58:53