C#-使用缓存进行延迟加载



我有一个存储库装饰器。这个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();
}

然而,你真的不应该这样做;您正在为所有内容共享相同的锁,这只会导致争用。

您希望您的锁尽可能细粒度,以免在锁定时阻塞其他等待线程。在这里使用共享锁不是细粒度的。

最新更新