0

我有一个用于值缓存功能的通用基类。

public abstract class CachedValueProviderBase<T> : ICachedValueProvider<T> where T : class
{
    private Cache Cache { set; get; }
    protected string CacheKey { get; set; }
    protected int CacheSpanInMinutes { get; set; }

    private static readonly object _cacheLock = new object();

    public T Values
    {
        get
        {
            T value = Cache[CacheKey] as T;
            if (value == null)
            {
                lock (_cacheLock)
                {
                    value = Cache[CacheKey] as T;
                    if (value == null)
                    {
                        value = InitializeCache();
                    }
                }
            }

            return value;
        }
    }

    protected CachedValueProviderBase()
    {
        Cache = HttpRuntime.Cache;
        CacheSpanInMinutes = 15;
    }

    public T CacheValue(T value)
    {
        if (value != null)
        {
            lock (_cacheLock)
            {
                Cache.Insert(CacheKey, value, null, DateTime.UtcNow.AddMinutes(CacheSpanInMinutes),
                             Cache.NoSlidingExpiration);
            }
        }

        return value;
    }

    private T InitializeCache()
    {
        T value = Initialize();
        CacheValue(value);

        return value;
    }

    protected abstract T Initialize();
}

我有几个使用这个基类的类,只要 T 不同就可以了。例如,当两个子类使用相同的 T,字符串时,它们共享相同的缓存锁定对象。在基类中实现逻辑但仍为每个子类提供自己的缓存锁定对象的最佳方法是什么?

更新 在以下建议之后,我更新了我的课程:

public abstract class CachedValueProviderBase<T> : ICachedValueProvider<T> where T : class
    {
        private Cache Cache { set; get; }
        protected string CacheKey { get; set; }
        protected int CacheSpanInMinutes { get; set; }
        private object _cacheLock = new object();

        public T Values
        {
            get
            {
                T value = Cache[CacheKey] as T;
                if (value == null)
                {
                    lock (_cacheLock)
                    {
                        value = Cache[CacheKey] as T;
                        if (value == null)
                        {
                            value = InitializeCache();
                        }
                    }
                }

                return value;
            }
        }

        protected CachedValueProviderBase()
        {
            Cache = HttpRuntime.Cache;
            CacheSpanInMinutes = 15;
        }

        public T CacheValue(T value)
        {
            if (value != null)
            {
                Cache.Insert(CacheKey, value, null, DateTime.UtcNow.AddMinutes(CacheSpanInMinutes),
                             Cache.NoSlidingExpiration);

            }

            return value;
        }

        private T InitializeCache()
        {
            T value = Initialize();
            CacheValue(value);

            return value;
        }

        protected abstract T Initialize();
    }
}

我的子类现在是单例的,所以我可以摆脱静态缓存锁对象,使其成为实例变量。

4

3 回答 3

1

我必须仔细查看您的代码,以确定它是否正确。一旦我注意到您的缓存是 a HttpRuntime.Cache,它就有意义了。HttpRuntime.Cache是线程安全的。否则你会有几个线程安全问题。使用您当前的代码,我建议您执行以下操作:

private string CacheKey { get; set; }

protected CachedValueProviderBase(string cacheKey)
{
    this.CacheKey = cacheKey + "_" + typeof(T).FullName;
}

通过提供cacheKeyas 构造函数参数并将属性设为私有(或 readonly 可以),您可以防止它稍后被更改。通过将类型名称附加到键,您可以防止缓存冲突,因为每个人都使用相同的缓存。

最后一点。lock方法中的是CacheValue多余的,因为Cache是线程安全的。

于 2012-05-18T09:12:05.283 回答
0

好吧,只需删除 cacheLock 对象上的 static 修饰符。

该关键字强制该字段在共享相同通用参数类型的子类的所有实例之间共享。

如果删除它,cacheLock 对象将对子类的每个实例都是私有的,而不管泛型参数的类型如何。

 private static readonly object _cacheLock = new object();

应该 :

 private readonly object _cacheLock = new object();

希望有帮助

于 2012-05-18T08:37:50.027 回答
0

我通过在我的基类 GetCacheLockObject() 中实现一个抽象方法来处理这个问题。

protected abstract object GetCacheLockObject();

然后每个派生类返回它自己对缓存锁对象的引用:

private static readonly object _cacheLockObject = new Object();

protected override object GetCacheLockObject()
{
    return _cacheLockObject;
}

调用锁定共享基类缓存代码然后引用此方法而不是基类中的对象。

于 2013-10-04T19:01:44.907 回答