/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the OpenSimulator Project nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ using System; using System.Collections; using System.Collections.Generic; using System.Threading; namespace OpenSim.Framework { /// <summary> /// Synchronized Cenome cache wrapper. /// </summary> /// <typeparam name="TKey"> /// The type of keys in the cache. /// </typeparam> /// <typeparam name="TValue"> /// The type of values in the cache. /// </typeparam> /// <remarks> /// <para> /// Enumerator will block other threads, until enumerator's <see cref="IDisposable.Dispose"/> method is called. /// "foreach" statement is automatically calling it. /// </para> /// </remarks> public class CnmSynchronizedCache<TKey, TValue> : ICnmCache<TKey, TValue> { /// <summary> /// The cache object. /// </summary> private readonly ICnmCache<TKey, TValue> m_cache; /// <summary> /// Synchronization root. /// </summary> private readonly object m_syncRoot; /// <summary> /// Initializes a new instance of the <see cref="CnmSynchronizedCache{TKey,TValue}"/> class. /// Initializes a new instance of the <see cref="CnmSynchronizedCache{TKey,TValue}"/> class. /// </summary> /// <param name="cache"> /// The cache. /// </param> private CnmSynchronizedCache(ICnmCache<TKey, TValue> cache) { m_cache = cache; m_syncRoot = m_cache.SyncRoot; } /// <summary> /// Returns a <see cref="ICnmCache{TKey,TValue}"/> wrapper that is synchronized (thread safe). /// </summary> /// <param name="cache"> /// The <see cref="ICnmCache{TKey,TValue}"/> to synchronize. /// </param> /// <returns> /// A <see cref="ICnmCache{TKey,TValue}"/> wrapper that is synchronized (thread safe). /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="cache"/>is null. /// </exception> public static ICnmCache<TKey, TValue> Synchronized(ICnmCache<TKey, TValue> cache) { if (cache == null) throw new ArgumentNullException("cache"); return cache.IsSynchronized ? cache : new CnmSynchronizedCache<TKey, TValue>(cache); } #region Nested type: SynchronizedEnumerator /// <summary> /// Synchronized enumerator. /// </summary> private class SynchronizedEnumerator : IEnumerator<KeyValuePair<TKey, TValue>> { /// <summary> /// Enumerator that is being synchronized. /// </summary> private readonly IEnumerator<KeyValuePair<TKey, TValue>> m_enumerator; /// <summary> /// Synchronization root. /// </summary> private object m_syncRoot; /// <summary> /// Initializes a new instance of the <see cref="SynchronizedEnumerator"/> class. /// </summary> /// <param name="enumerator"> /// The enumerator that is being synchronized. /// </param> /// <param name="syncRoot"> /// The sync root. /// </param> public SynchronizedEnumerator(IEnumerator<KeyValuePair<TKey, TValue>> enumerator, object syncRoot) { m_syncRoot = syncRoot; m_enumerator = enumerator; Monitor.Enter(m_syncRoot); } /// <summary> /// Finalizes an instance of the <see cref="SynchronizedEnumerator"/> class. /// </summary> ~SynchronizedEnumerator() { Dispose(); } #region IEnumerator<KeyValuePair<TKey,TValue>> Members /// <summary> /// Gets the element in the collection at the current position of the enumerator. /// </summary> /// <returns> /// The element in the collection at the current position of the enumerator. /// </returns> /// <exception cref="InvalidOperationException"> /// The enumerator has reach end of collection or <see cref="MoveNext"/> is not called. /// </exception> public KeyValuePair<TKey, TValue> Current { get { return m_enumerator.Current; } } /// <summary> /// Gets the current element in the collection. /// </summary> /// <returns> /// The current element in the collection. /// </returns> /// <exception cref="InvalidOperationException"> /// The enumerator is positioned before the first element of the collection or after the last element. /// </exception><filterpriority>2</filterpriority> object IEnumerator.Current { get { return Current; } } /// <summary> /// Releases synchronization lock. /// </summary> public void Dispose() { if (m_syncRoot != null) { Monitor.Exit(m_syncRoot); m_syncRoot = null; } m_enumerator.Dispose(); GC.SuppressFinalize(this); } /// <summary> /// Advances the enumerator to the next element of the collection. /// </summary> /// <returns> /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. /// </returns> /// <exception cref="InvalidOperationException"> /// The collection was modified after the enumerator was created. /// </exception> public bool MoveNext() { return m_enumerator.MoveNext(); } /// <summary> /// Sets the enumerator to its initial position, which is before the first element in the collection. /// </summary> /// <exception cref="InvalidOperationException"> /// The collection was modified after the enumerator was created. /// </exception> public void Reset() { m_enumerator.Reset(); } #endregion } #endregion #region ICnmCache<TKey,TValue> Members /// <summary> /// Gets current count of elements stored to <see cref="ICnmCache{TKey,TValue}"/>. /// </summary> /// <remarks> /// <para> /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. /// </para> /// </remarks> /// <seealso cref="ICnmCache{TKey,TValue}.MaxCount"/> /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/> /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/> /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/> public int Count { get { lock (m_syncRoot) { return m_cache.Count; } } } /// <summary> /// Gets or sets elements expiration time. /// </summary> /// <value> /// Elements expiration time. /// </value> /// <remarks> /// <para> /// When element has been stored in <see cref="ICnmCache{TKey,TValue}"/> longer than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> /// and it is not accessed through <see cref="ICnmCache{TKey,TValue}.TryGetValue"/> method or element's value is /// not replaced by <see cref="ICnmCache{TKey,TValue}.Set"/> method, then it is automatically removed from the /// <see cref="ICnmCache{TKey,TValue}"/>. /// </para> /// <para> /// It is possible that <see cref="ICnmCache{TKey,TValue}"/> implementation removes element before it's expiration time, /// because total size or count of elements stored to cache is larger than <see cref="ICnmCache{TKey,TValue}.MaxSize"/> or <see cref="ICnmCache{TKey,TValue}.MaxCount"/>. /// </para> /// <para> /// It is also possible that element stays in cache longer than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/>. /// </para> /// <para> /// Calling <see cref="ICnmCache{TKey,TValue}.PurgeExpired"/> try to remove all elements that are expired. /// </para> /// <para> /// To disable time limit in cache, set <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> to <see cref="DateTime.MaxValue"/>. /// </para> /// </remarks> /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/> /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/> /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/> /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/> /// <seealso cref="ICnmCache{TKey,TValue}.Count"/> /// <seealso cref="ICnmCache{TKey,TValue}.MaxCount"/> /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/> /// <seealso cref="ICnmCache{TKey,TValue}.Size"/> public TimeSpan ExpirationTime { get { lock (m_syncRoot) { return m_cache.ExpirationTime; } } set { lock (m_syncRoot) { m_cache.ExpirationTime = value; } } } /// <summary> /// Gets a value indicating whether <see cref="ICnmCache{TKey,TValue}"/> is limiting count of elements. /// </summary> /// <value> /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> count of elements is limited; /// otherwise, <see langword="false"/>. /// </value> /// <remarks> /// <para> /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. /// </para> /// </remarks> /// <seealso cref="ICnmCache{TKey,TValue}.Count"/> /// <seealso cref="ICnmCache{TKey,TValue}.MaxCount"/> /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/> /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/> public bool IsCountLimited { get { lock (m_syncRoot) { return m_cache.IsCountLimited; } } } /// <summary> /// Gets a value indicating whether <see cref="ICnmCache{TKey,TValue}"/> is limiting size of elements. /// </summary> /// <value> /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> total size of elements is limited; /// otherwise, <see langword="false"/>. /// </value> /// <remarks> /// <para> /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. /// </para> /// </remarks> /// <seealso cref="ICnmCache{TKey,TValue}.MaxElementSize"/> /// <seealso cref="ICnmCache{TKey,TValue}.Size"/> /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/> /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/> /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/> public bool IsSizeLimited { get { lock (m_syncRoot) { return m_cache.IsSizeLimited; } } } /// <summary> /// Gets a value indicating whether or not access to the <see cref="ICnmCache{TKey,TValue}"/> is synchronized (thread safe). /// </summary> /// <value> /// <see langword="true"/> if access to the <see cref="ICnmCache{TKey,TValue}"/> is synchronized (thread safe); /// otherwise, <see langword="false"/>. /// </value> /// <remarks> /// <para> /// To get synchronized (thread safe) access to <see cref="ICnmCache{TKey,TValue}"/> object, use /// <see cref="CnmSynchronizedCache{TKey,TValue}.Synchronized"/> in <see cref="CnmSynchronizedCache{TKey,TValue}"/> class /// to retrieve synchronized wrapper for <see cref="ICnmCache{TKey,TValue}"/> object. /// </para> /// </remarks> /// <seealso cref="ICnmCache{TKey,TValue}.SyncRoot"/> /// <seealso cref="CnmSynchronizedCache{TKey,TValue}"/> public bool IsSynchronized { get { return true; } } /// <summary> /// Gets a value indicating whether elements stored to <see cref="ICnmCache{TKey,TValue}"/> have limited inactivity time. /// </summary> /// <value> /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> has a fixed total size of elements; /// otherwise, <see langword="false"/>. /// </value> /// <remarks> /// If <see cref="ICnmCache{TKey,TValue}"/> have limited inactivity time and element is not accessed through <see cref="ICnmCache{TKey,TValue}.Set"/> /// or <see cref="ICnmCache{TKey,TValue}.TryGetValue"/> methods in <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> , then element is automatically removed from /// the cache. Depending on implementation of the <see cref="ICnmCache{TKey,TValue}"/>, some of the elements may /// stay longer in cache. /// </remarks> /// <seealso cref="ICnmCache{TKey,TValue}.ExpirationTime"/> /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/> /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/> /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/> public bool IsTimeLimited { get { lock (m_syncRoot) { return m_cache.IsTimeLimited; } } } /// <summary> /// Gets or sets maximal allowed count of elements that can be stored to <see cref="ICnmCache{TKey,TValue}"/>. /// </summary> /// <value> /// <see cref="int.MaxValue"/>, if <see cref="ICnmCache{TKey,TValue}"/> is not limited by count of elements; /// otherwise maximal allowed count of elements. /// </value> /// <remarks> /// <para> /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. /// </para> /// </remarks> public int MaxCount { get { lock (m_syncRoot) { return m_cache.MaxCount; } } set { lock (m_syncRoot) { m_cache.MaxCount = value; } } } /// <summary> /// <para>Gets maximal allowed element size.</para> /// </summary> /// <value> /// Maximal allowed element size. /// </value> /// <remarks> /// <para> /// If element's size is larger than <see cref="ICnmCache{TKey,TValue}.MaxElementSize"/>, then element is /// not added to the <see cref="ICnmCache{TKey,TValue}"/>. /// </para> /// </remarks> /// <seealso cref="ICnmCache{TKey,TValue}.Set"/> /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/> /// <seealso cref="ICnmCache{TKey,TValue}.Size"/> /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/> public long MaxElementSize { get { lock (m_syncRoot) { return m_cache.MaxElementSize; } } } /// <summary> /// Gets or sets maximal allowed total size for elements stored to <see cref="ICnmCache{TKey,TValue}"/>. /// </summary> /// <value> /// Maximal allowed total size for elements stored to <see cref="ICnmCache{TKey,TValue}"/>. /// </value> /// <remarks> /// <para> /// Normally size is total bytes used by elements in the cache. But it can be any other suitable unit of measure. /// </para> /// <para> /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. /// </para> /// </remarks> /// <exception cref="ArgumentOutOfRangeException">value is less than 0.</exception> /// <seealso cref="ICnmCache{TKey,TValue}.MaxElementSize"/> /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/> /// <seealso cref="ICnmCache{TKey,TValue}.Size"/> public long MaxSize { get { lock (m_syncRoot) { return m_cache.MaxSize; } } set { lock (m_syncRoot) { m_cache.MaxSize = value; } } } /// <summary> /// Gets total size of elements stored to <see cref="ICnmCache{TKey,TValue}"/>. /// </summary> /// <value> /// Total size of elements stored to <see cref="ICnmCache{TKey,TValue}"/>. /// </value> /// <remarks> /// <para> /// Normally bytes, but can be any suitable unit of measure. /// </para> /// <para> /// Element's size is given when element is added or replaced by <see cref="ICnmCache{TKey,TValue}.Set"/> method. /// </para> /// <para> /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. /// </para> /// </remarks> /// <seealso cref="ICnmCache{TKey,TValue}.MaxElementSize"/> /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/> /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/> /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/> /// <seealso cref="ICnmCache{TKey,TValue}.ExpirationTime"/> public long Size { get { lock (m_syncRoot) { return m_cache.Size; } } } /// <summary> /// Gets an object that can be used to synchronize access to the <see cref="ICnmCache{TKey,TValue}"/>. /// </summary> /// <value> /// An object that can be used to synchronize access to the <see cref="ICnmCache{TKey,TValue}"/>. /// </value> /// <remarks> /// <para> /// To get synchronized (thread safe) access to <see cref="ICnmCache{TKey,TValue}"/>, use <see cref="CnmSynchronizedCache{TKey,TValue}"/> /// method <see cref="CnmSynchronizedCache{TKey,TValue}.Synchronized"/> to retrieve synchronized wrapper interface to /// <see cref="ICnmCache{TKey,TValue}"/>. /// </para> /// </remarks> /// <seealso cref="ICnmCache{TKey,TValue}.IsSynchronized"/> /// <seealso cref="CnmSynchronizedCache{TKey,TValue}"/> public object SyncRoot { get { return m_syncRoot; } } /// <summary> /// Removes all elements from the <see cref="ICnmCache{TKey,TValue}"/>. /// </summary> /// <seealso cref="ICnmCache{TKey,TValue}.Set"/> /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/> /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/> /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/> /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/> public void Clear() { lock (m_syncRoot) { m_cache.Clear(); } } /// <summary> /// Returns an enumerator that iterates through the elements stored to <see cref="ICnmCache{TKey,TValue}"/>. /// </summary> /// <returns> /// A <see cref="IEnumerator{T}"/> that can be used to iterate through the collection. /// </returns> /// <filterpriority>1</filterpriority> public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { lock (m_syncRoot) { return new SynchronizedEnumerator(m_cache.GetEnumerator(), m_syncRoot); } } /// <summary> /// Purge expired elements from the <see cref="ICnmCache{TKey,TValue}"/>. /// </summary> /// <remarks> /// <para> /// Element becomes expired when last access time to it has been longer time than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/>. /// </para> /// <para> /// Depending on <see cref="ICnmCache{TKey,TValue}"/> implementation, some of expired elements /// may stay longer than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> in the cache. /// </para> /// </remarks> /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/> /// <seealso cref="ICnmCache{TKey,TValue}.ExpirationTime"/> /// <seealso cref="ICnmCache{TKey,TValue}.Set"/> /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/> /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/> /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/> /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/> public void PurgeExpired() { lock (m_syncRoot) { m_cache.PurgeExpired(); } } /// <summary> /// Removes element associated with <paramref name="key"/> from the <see cref="ICnmCache{TKey,TValue}"/>. /// </summary> /// <param name="key"> /// The key that is associated with element to remove from the <see cref="ICnmCache{TKey,TValue}"/>. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="key"/>is <see langword="null"/>. /// </exception> /// <seealso cref="ICnmCache{TKey,TValue}.Set"/> /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/> /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/> /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/> /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/> public void Remove(TKey key) { lock (m_syncRoot) { m_cache.Remove(key); } } /// <summary> /// Removes elements that are associated with one of <paramref name="keys"/> from the <see cref="ICnmCache{TKey,TValue}"/>. /// </summary> /// <param name="keys"> /// The keys that are associated with elements to remove from the <see cref="ICnmCache{TKey,TValue}"/>. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="keys"/>is <see langword="null"/>. /// </exception> /// <seealso cref="ICnmCache{TKey,TValue}.Set"/> /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/> /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/> /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/> /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/> public void RemoveRange(IEnumerable<TKey> keys) { lock (m_syncRoot) { m_cache.RemoveRange(keys); } } /// <summary> /// Add or replace an element with the provided <paramref name="key"/>, <paramref name="value"/> and <paramref name="size"/> to /// <see cref="ICnmCache{TKey,TValue}"/>. /// </summary> /// <param name="key"> /// The object used as the key of the element. Can't be <see langword="null"/> reference. /// </param> /// <param name="value"> /// The object used as the value of the element to add or replace. <see langword="null"/> is allowed. /// </param> /// <param name="size"> /// The element's size. Normally bytes, but can be any suitable unit of measure. /// </param> /// <returns> /// <see langword="true"/>if element has been added successfully to the <see cref="ICnmCache{TKey,TValue}"/>; /// otherwise <see langword="false"/>. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="key"/>is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// The element's <paramref name="size"/> is less than 0. /// </exception> /// <remarks> /// <para> /// If element's <paramref name="size"/> is larger than <see cref="ICnmCache{TKey,TValue}.MaxElementSize"/>, then element is /// not added to the <see cref="ICnmCache{TKey,TValue}"/>, however - possible older element is /// removed from the <see cref="ICnmCache{TKey,TValue}"/>. /// </para> /// <para> /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, /// <see cref="ICnmCache{TKey,TValue}"/>will remove less recently used elements until it can fit an new element. /// </para> /// <para> /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, /// <see cref="ICnmCache{TKey,TValue}"/>will remove less recently used elements until it can fit an new element. /// </para> /// </remarks> /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/> /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/> /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/> /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/> /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/> /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/> /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/> public bool Set(TKey key, TValue value, long size) { lock (m_syncRoot) { return m_cache.Set(key, value, size); } } /// <summary> /// Gets the <paramref name="value"/> associated with the specified <paramref name="key"/>. /// </summary> /// <returns> /// <see langword="true"/>if the <see cref="ICnmCache{TKey,TValue}"/> contains an element with /// the specified key; otherwise, <see langword="false"/>. /// </returns> /// <param name="key"> /// The key whose <paramref name="value"/> to get. /// </param> /// <param name="value"> /// When this method returns, the value associated with the specified <paramref name="key"/>, /// if the <paramref name="key"/> is found; otherwise, the /// default value for the type of the <paramref name="value"/> parameter. This parameter is passed uninitialized. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="key"/>is <see langword="null"/>. /// </exception> /// <seealso cref="ICnmCache{TKey,TValue}.Set"/> /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/> /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/> /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/> /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/> public bool TryGetValue(TKey key, out TValue value) { lock (m_syncRoot) { return m_cache.TryGetValue(key, out value); } } /// <summary> /// Returns an enumerator that iterates through the elements stored to <see cref="ICnmCache{TKey,TValue}"/>. /// </summary> /// <returns> /// A <see cref="IEnumerator"/> that can be used to iterate through the collection. /// </returns> /// <filterpriority>1</filterpriority> IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion } }