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が異なる限り問題ありません。たとえば、2つのサブクラスが同じ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();
    }
}

私のサブクラスはシングルトンになっているので、静的なcachelockオブジェクトを取り除き、インスタンス変数にすることができます。

4

3 に答える 3

1

私はあなたのコードをよく見て、それが正しいかどうかを確かめなければなりませんでした。あなたのキャッシュがであることに気づいたらHttpRuntime.Cache、それは理にかなっています。はHttpRuntime.Cacheスレッドセーフです。そうしないと、スレッドセーフの問題がいくつか発生します。現在のコードでは、次のことを行うことをお勧めします。

private string CacheKey { get; set; }

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

ascacheKeyコンストラクター引数を指定し、プロパティをプライベートにする(または読み取り専用にする)ことで、後で変更されないようにします。キーにタイプ名を追加することで、全員が同じキャッシュを使用しているため、キャッシュの競合を防ぐことができます。

最後にもう1つ。はスレッドセーフであるため、このメソッドのlockinCacheValueは冗長です。Cache

于 2012-05-18T09:12:05.283 に答える
0

さて、cacheLockオブジェクトの静的修飾子を削除するだけです。

そのキーワードは、同じ汎用パラメーター型を共有するサブクラスのすべてのインスタンス間でフィールドを強制的に共有します。

これを削除すると、ジェネリックパラメーターのタイプに関係なく、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 に答える