C# 在泛型基类中使用静态对象进行缓存锁定

C# 在泛型基类中使用静态对象进行缓存锁定,c#,generics,caching,C#,Generics,Caching,我有一个用于值缓存功能的通用基类 public abstract class CachedValueProviderBase<T> : ICachedValueProvider<T> where T : class { private Cache Cache { set; get; } protected string CacheKey { get; set; } protected int CacheSpanInMinutes { get; se

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

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();
}
公共抽象类CachedValueProviderBase:ICachedValueProvider其中T:class
{
专用缓存{set;get;}
受保护的字符串缓存键{get;set;}
受保护的int CacheSpanInMinutes{get;set;}
私有静态只读对象_cacheLock=new object();
公共价值观
{
得到
{
T值=缓存[CacheKey]为T;
如果(值==null)
{
锁(_cacheLock)
{
value=Cache[CacheKey]作为T;
如果(值==null)
{
值=InitializeCache();
}
}
}
返回值;
}
}
受保护的CachedValueProviderBase()
{
Cache=HttpRuntime.Cache;
CacheSpanInMinutes=15;
}
公共缓存值(T值)
{
if(值!=null)
{
锁(_cacheLock)
{
Insert(CacheKey,value,null,DateTime.UtcNow.AddMinutes(CacheSpanInMinutes),
Cache.NoSlidingExpiration);
}
}
返回值;
}
私人T InitializeCache()
{
T值=初始化();
缓存值(value);
返回值;
}
受保护的抽象T初始化();
}
我有几个类使用这个基类,只要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();
    }
}
公共抽象类CachedValueProviderBase:ICachedValueProvider其中T:class
{
专用缓存{set;get;}
受保护的字符串缓存键{get;set;}
受保护的int CacheSpanInMinutes{get;set;}
私有对象_cacheLock=新对象();
公共价值观
{
得到
{
T值=缓存[CacheKey]为T;
如果(值==null)
{
锁(_cacheLock)
{
value=Cache[CacheKey]作为T;
如果(值==null)
{
值=InitializeCache();
}
}
}
返回值;
}
}
受保护的CachedValueProviderBase()
{
Cache=HttpRuntime.Cache;
CacheSpanInMinutes=15;
}
公共缓存值(T值)
{
if(值!=null)
{
Insert(CacheKey,value,null,DateTime.UtcNow.AddMinutes(CacheSpanInMinutes),
Cache.NoSlidingExpiration);
}
返回值;
}
私人T InitializeCache()
{
T值=初始化();
缓存值(value);
返回值;
}
受保护的抽象T初始化();
}
}

我的子类现在是单例的,因此我可以去掉静态cachelock对象,使其成为实例变量。

好吧,只需删除cachelock对象上的静态修饰符

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

如果删除它,则cacheLock对象将是子类的每个实例的私有对象,而与泛型参数的类型无关

 private static readonly object _cacheLock = new object();
应该是:

 private readonly object _cacheLock = new object();

希望这对我有所帮助,我必须仔细看看你的代码,看看它是否正确。一旦我注意到你的缓存是一个
HttpRuntime.cache
,它就有意义了。
HttpRuntime.Cache
是线程安全的。否则,您将有几个线程安全问题。根据当前代码,我建议您执行以下操作:

private string CacheKey { get; set; }

protected CachedValueProviderBase(string cacheKey)
{
    this.CacheKey = cacheKey + "_" + typeof(T).FullName;
}
通过提供
cacheKey
作为构造函数参数并将属性设置为私有(或者只读),可以防止以后更改它。通过将类型名称附加到键,可以防止缓存冲突,因为每个人都使用相同的缓存


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

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

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

private static readonly object _cacheLockObject = new Object();

protected override object GetCacheLockObject()
{
    return _cacheLockObject;
}

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

这是在Web服务器上运行的,因此我仍然必须为多个线程锁定缓存。当移除静态时,可能有多个线程初始化缓存。然后,您应该考虑使用缓存提供程序,这样,无论线程访问它,您都有一个缓存,为每个缓存实例保留唯一的缓存锁。@b3n如果您使用的是.net 4.0,则可以使用
Lazy
进行线程安全初始化。不管怎样,静态锁对于实例方法来说是一件坏事。如果我遵循单例路径,我怎么能把上面的代码保存在基类中呢?我必须将缓存锁向下拉到子类,这样基类就会在它试图锁定的地方中断。否。singleton模式与此无关,它用于保证您在整个应用程序中拥有一个唯一的对象实例。但是,您需要使用单例模式的线程安全实现。它不会破坏缓存提供程序的实现。所以我可以基本上去掉缓存锁对象,看看缓存是线程安全的吗?这取决于
private static readonly object _cacheLockObject = new Object();

protected override object GetCacheLockObject()
{
    return _cacheLockObject;
}