/* **************************************************************************** * * Copyright (c) Microsoft Corporation. All rights reserved. * * This software is subject to the Microsoft Public License (Ms-PL). * A copy of the license can be found in the license.htm file included * in this distribution. * * You must not remove this notice, or any other, from this software. * * ***************************************************************************/ namespace System.Web.Mvc { using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Threading; [SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable", Justification = "Instances of this type are meant to be singletons.")] internal abstract class ReaderWriterCache { private readonly Dictionary _cache; private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(); protected ReaderWriterCache() : this(null) { } protected ReaderWriterCache(IEqualityComparer comparer) { _cache = new Dictionary(comparer); } protected Dictionary Cache { get { return _cache; } } protected TValue FetchOrCreateItem(TKey key, Func creator) { // first, see if the item already exists in the cache _rwLock.EnterReadLock(); try { TValue existingEntry; if (_cache.TryGetValue(key, out existingEntry)) { return existingEntry; } } finally { _rwLock.ExitReadLock(); } // insert the new item into the cache TValue newEntry = creator(); _rwLock.EnterWriteLock(); try { TValue existingEntry; if (_cache.TryGetValue(key, out existingEntry)) { // another thread already inserted an item, so use that one return existingEntry; } _cache[key] = newEntry; return newEntry; } finally { _rwLock.ExitWriteLock(); } } } }