ConcurrentDictionary.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Collections / Concurrent / ConcurrentDictionary.cs / 1305376 / ConcurrentDictionary.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//
// [....] 
/*============================================================ 
**
** Class:   ConcurrentDictionary 
**
**
** Purpose: A scalable dictionary for concurrent access
** 
**
===========================================================*/ 
 
// If CDS_COMPILE_JUST_THIS symbol is defined, the ConcurrentDictionary.cs file compiles separately,
// with no dependencies other than .NET Framework 3.5. 

//#define CDS_COMPILE_JUST_THIS

using System; 
using System.Collections.Generic;
using System.Text; 
using System.Threading; 
using System.Runtime.InteropServices;
using System.Diagnostics; 
using System.Collections;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions; 
using System.Collections.ObjectModel;
 
#if !CDS_COMPILE_JUST_THIS 
using System.Diagnostics.Contracts;
#endif 

namespace System.Collections.Concurrent
{
 
    /// 
    /// Represents a thread-safe collection of keys and values. 
    ///  
    /// The type of the keys in the dictionary.
    /// The type of the values in the dictionary. 
    /// 
    /// All public and protected members of  are thread-safe and may be used
    /// concurrently from multiple threads.
    ///  
    [Serializable]
    [ComVisible(false)] 
    [DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<,>))] 
    [DebuggerDisplay("Count = {Count}")]
    [HostProtection(Synchronization = true, ExternalThreading = true)] 
    public class ConcurrentDictionary : IDictionary, IDictionary
    {
        [NonSerialized]
        private volatile Node[] m_buckets; // A singly-linked list for each bucket. 
        [NonSerialized]
        private object[] m_locks; // A set of locks, each guarding a section of the table. 
        [NonSerialized] 
        private volatile int[] m_countPerLock; // The number of elements guarded by each lock.
        private IEqualityComparer m_comparer; // Key equality comparer 

        private KeyValuePair[] m_serializationArray; // Used for custom serialization

        private int m_serializationConcurrencyLevel; // used to save the concurrency level in serialization 

        private int m_serializationCapacity; // used to save the capacity in serialization 
 
        // The default concurrency level is DEFAULT_CONCURRENCY_MULTIPLIER * #CPUs. The higher the
        // DEFAULT_CONCURRENCY_MULTIPLIER, the more concurrent writes can take place without interference 
        // and blocking, but also the more expensive operations that require all locks become (e.g. table
        // resizing, ToArray, Count, etc). According to brief benchmarks that we ran, 4 seems like a good
        // compromise.
        private const int DEFAULT_CONCURRENCY_MULTIPLIER = 4; 

        // The default capacity, i.e. the initial # of buckets. When choosing this value, we are making 
        // a trade-off between the size of a very small dictionary, and the number of resizes when 
        // constructing a large dictionary. Also, the capacity should not be divisible by a small prime.
        private const int DEFAULT_CAPACITY = 31; 

        /// 
        /// Initializes a new instance of the  
        /// class that is empty, has the default concurrency level, has the default initial capacity, and
        /// uses the default comparer for the key type. 
        ///  
        public ConcurrentDictionary() : this(DefaultConcurrencyLevel, DEFAULT_CAPACITY) { }
 
        /// 
        /// Initializes a new instance of the 
        /// class that is empty, has the specified concurrency level and capacity, and uses the default 
        /// comparer for the key type.
        ///  
        /// The estimated number of threads that will update the 
        ///  concurrently.
        /// The initial number of elements that the 
        /// can contain.
        ///  is
        /// less than 1. 
        ///   is less than
        /// 0. 
        public ConcurrentDictionary(int concurrencyLevel, int capacity) : this(concurrencyLevel, capacity, EqualityComparer.Default) { } 

        ///  
        /// Initializes a new instance of the 
        /// class that contains elements copied from the specified , has the default concurrency
        /// level, has the default initial capacity, and uses the default comparer for the key type. 
        /// 
        /// The  whose elements are copied to 
        /// the new
        /// . 
        ///  is a null reference
        /// (Nothing in Visual Basic).
        ///  contains one or more
        /// duplicate keys. 
        public ConcurrentDictionary(IEnumerable> collection) : this(collection, EqualityComparer.Default) { }
 
        ///  
        /// Initializes a new instance of the 
        /// class that is empty, has the specified concurrency level and capacity, and uses the specified 
        /// .
        /// 
        /// The 
        /// implementation to use when comparing keys. 
        ///  is a null reference
        /// (Nothing in Visual Basic). 
        public ConcurrentDictionary(IEqualityComparer comparer) : this(DefaultConcurrencyLevel, DEFAULT_CAPACITY, comparer) { } 

        ///  
        /// Initializes a new instance of the 
        /// class that contains elements copied from the specified , has the default concurrency level, has the default
        /// initial capacity, and uses the specified 
        /// .
        ///  
        /// The  whose elements are copied to
        /// the new 
        /// .
        /// The 
        /// implementation to use when comparing keys.
        ///  is a null reference 
        /// (Nothing in Visual Basic). -or-
        ///  is a null reference (Nothing in Visual Basic). 
        ///  
        public ConcurrentDictionary(IEnumerable> collection, IEqualityComparer comparer)
            : this(DefaultConcurrencyLevel, collection, comparer) { } 

        /// 
        /// Initializes a new instance of the 
        /// class that contains elements copied from the specified , 
        /// has the specified concurrency level, has the specified initial capacity, and uses the specified
        /// . 
        ///  
        /// The estimated number of threads that will update the
        ///  concurrently. 
        /// The  whose elements are copied to the new
        /// .
        /// The  implementation to use
        /// when comparing keys. 
        /// 
        ///  is a null reference (Nothing in Visual Basic). 
        /// -or- 
        ///  is a null reference (Nothing in Visual Basic).
        ///  
        /// 
        ///  is less than 1.
        /// 
        ///  contains one or more duplicate keys. 
        public ConcurrentDictionary(
            int concurrencyLevel, IEnumerable> collection, IEqualityComparer comparer) 
            : this(concurrencyLevel, DEFAULT_CAPACITY, comparer) 
        {
            if (collection == null) throw new ArgumentNullException("collection"); 
            if (comparer == null) throw new ArgumentNullException("comparer");

            InitializeFromCollection(collection);
        } 

        private void InitializeFromCollection(IEnumerable> collection) 
        { 
            TValue dummy;
            foreach (KeyValuePair pair in collection) 
            {
                if (pair.Key == null) throw new ArgumentNullException("key");

                if (!TryAddInternal(pair.Key, pair.Value, false, false, out dummy)) 
                {
                    throw new ArgumentException(GetResource("ConcurrentDictionary_SourceContainsDuplicateKeys")); 
                } 
            }
        } 

        /// 
        /// Initializes a new instance of the 
        /// class that is empty, has the specified concurrency level, has the specified initial capacity, and 
        /// uses the specified .
        ///  
        /// The estimated number of threads that will update the 
        ///  concurrently.
        /// The initial number of elements that the 
        /// can contain.
        /// The 
        /// implementation to use when comparing keys. 
        /// 
        ///  is less than 1. -or- 
        ///  is less than 0. 
        /// 
        ///  is a null reference 
        /// (Nothing in Visual Basic).
        public ConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer comparer)
        {
            if (concurrencyLevel < 1) 
            {
                throw new ArgumentOutOfRangeException("concurrencyLevel", GetResource("ConcurrentDictionary_ConcurrencyLevelMustBePositive")); 
            } 
            if (capacity < 0)
            { 
                throw new ArgumentOutOfRangeException("capacity", GetResource("ConcurrentDictionary_CapacityMustNotBeNegative"));
            }
            if (comparer == null) throw new ArgumentNullException("comparer");
 
            // The capacity should be at least as large as the concurrency level. Otherwise, we would have locks that don't guard
            // any buckets. 
            if (capacity < concurrencyLevel) 
            {
                capacity = concurrencyLevel; 
            }

            m_locks = new object[concurrencyLevel];
            for (int i = 0; i < m_locks.Length; i++) 
            {
                m_locks[i] = new object(); 
            } 

            m_countPerLock = new int[m_locks.Length]; 
            m_buckets = new Node[capacity];
            m_comparer = comparer;
        }
 

        ///  
        /// Attempts to add the specified key and value to the .
        ///  
        /// The key of the element to add.
        /// The value of the element to add. The value can be a null reference (Nothing
        /// in Visual Basic) for reference types.
        /// true if the key/value pair was added to the 
        /// successfully; otherwise, false. 
        ///  is null reference 
        /// (Nothing in Visual Basic).
        /// The  
        /// contains too many elements.
        public bool TryAdd(TKey key, TValue value)
        {
            if (key == null) throw new ArgumentNullException("key"); 
            TValue dummy;
            return TryAddInternal(key, value, false, true, out dummy); 
        } 

        ///  
        /// Determines whether the  contains the specified
        /// key.
        /// 
        /// The key to locate in the .
        /// true if the  contains an element with 
        /// the specified key; otherwise, false. 
        ///  is a null reference
        /// (Nothing in Visual Basic). 
        public bool ContainsKey(TKey key)
        {
            if (key == null) throw new ArgumentNullException("key");
 
            TValue throwAwayValue;
            return TryGetValue(key, out throwAwayValue); 
        } 

        ///  
        /// Attempts to remove and return the the value with the specified key from the
        /// .
        /// 
        /// The key of the element to remove and return. 
        /// When this method returns,  contains the object removed from the
        ///  or the default value of  
        /// if the operation failed.
        /// true if an object was removed successfully; otherwise, false. 
        ///  is a null reference
        /// (Nothing in Visual Basic).
        public bool TryRemove(TKey key, out TValue value)
        { 
            if (key == null) throw new ArgumentNullException("key");
 
            return TryRemoveInternal(key, out value, false, default(TValue)); 
        }
 
        /// 
        /// Removes the specified key from the dictionary if it exists and returns its associated value.
        /// If matchValue flag is set, the key will be removed only if is associated with a particular
        /// value. 
        /// 
        /// The key to search for and remove if it exists. 
        /// The variable into which the removed value, if found, is stored. 
        /// Whether removal of the key is conditional on its value.
        /// The conditional value to compare against if  is true 
        /// 
        private bool TryRemoveInternal(TKey key, out TValue value, bool matchValue, TValue oldValue)
        {
            while (true) 
            {
                Node[] buckets = m_buckets; 
 
                int bucketNo, lockNo;
                GetBucketAndLockNo(m_comparer.GetHashCode(key), out bucketNo, out lockNo, buckets.Length); 

                lock (m_locks[lockNo])
                {
                    // If the table just got resized, we may not be holding the right lock, and must retry. 
                    // This should be a rare occurence.
                    if (buckets != m_buckets) 
                    { 
                        continue;
                    } 

                    Node prev = null;
                    for (Node curr = m_buckets[bucketNo]; curr != null; curr = curr.m_next)
                    { 
                        Assert((prev == null && curr == m_buckets[bucketNo]) || prev.m_next == curr);
 
                        if (m_comparer.Equals(curr.m_key, key)) 
                        {
                            if (matchValue) 
                            {
                                bool valuesMatch = EqualityComparer.Default.Equals(oldValue, curr.m_value);
                                if (!valuesMatch)
                                { 
                                    value = default(TValue);
                                    return false; 
                                } 
                            }
 
                            if (prev == null)
                            {
                                m_buckets[bucketNo] = curr.m_next;
                            } 
                            else
                            { 
                                prev.m_next = curr.m_next; 
                            }
 
                            value = curr.m_value;
                            m_countPerLock[lockNo]--;
                            return true;
                        } 
                        prev = curr;
                    } 
                } 

                value = default(TValue); 
                return false;
            }
        }
 
        /// 
        /// Attempts to get the value associated with the specified key from the . 
        /// 
        /// The key of the value to get. 
        /// When this method returns,  contains the object from
        /// the
        ///  with the spedified key or the default value of
        /// , if the operation failed. 
        /// true if the key was found in the ;
        /// otherwise, false. 
        ///  is a null reference 
        /// (Nothing in Visual Basic).
        public bool TryGetValue(TKey key, out TValue value) 
        {
            if (key == null) throw new ArgumentNullException("key");

            int bucketNo, lockNoUnused; 

            // We must capture the m_buckets field in a local variable. It is set to a new table on each table resize. 
            Node[] buckets = m_buckets; 
            GetBucketAndLockNo(m_comparer.GetHashCode(key), out bucketNo, out lockNoUnused, buckets.Length);
 
            // We can get away w/out a lock here.
            Node n = buckets[bucketNo];

            // The memory barrier ensures that the load of the fields of 'n' doesn’t move before the load from buckets[i]. 
            Thread.MemoryBarrier();
            while (n != null) 
            { 
                if (m_comparer.Equals(n.m_key, key))
                { 
                    value = n.m_value;
                    return true;
                }
                n = n.m_next; 
            }
 
            value = default(TValue); 
            return false;
        } 

        /// 
        /// Compares the existing value for the specified key with a specified value, and if they’re equal,
        /// updates the key with a third value. 
        /// 
        /// The key whose value is compared with  and 
        /// possibly replaced. 
        /// The value that replaces the value of the element with  if the comparison results in equality. 
        /// The value that is compared to the value of the element with
        /// .
        /// true if the value with  was equal to  and replaced with ; otherwise, 
        /// false.
        ///  is a null 
        /// reference. 
        public bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue)
        { 
            if (key == null) throw new ArgumentNullException("key");

            int hashcode = m_comparer.GetHashCode(key);
            IEqualityComparer valueComparer = EqualityComparer.Default; 

            while (true) 
            { 
                int bucketNo;
                int lockNo; 

                Node[] buckets = m_buckets;
                GetBucketAndLockNo(hashcode, out bucketNo, out lockNo, buckets.Length);
 
                lock (m_locks[lockNo])
                { 
                    // If the table just got resized, we may not be holding the right lock, and must retry. 
                    // This should be a rare occurence.
                    if (buckets != m_buckets) 
                    {
                        continue;
                    }
 
                    // Try to find this key in the bucket
                    Node prev = null; 
                    for (Node node = buckets[bucketNo]; node != null; node = node.m_next) 
                    {
                        Assert((prev == null && node == m_buckets[bucketNo]) || prev.m_next == node); 
                        if (m_comparer.Equals(node.m_key, key))
                        {
                            if (valueComparer.Equals(node.m_value, comparisonValue))
                            { 
                                // Replace the old node with a new node. Unfortunately, we cannot simply
                                // change node.m_value in place. We don't know the size of TValue, so 
                                // its writes may not be atomic. 
                                Node newNode = new Node(node.m_key, newValue, hashcode, node.m_next);
 
                                if (prev == null)
                                {
                                    buckets[bucketNo] = newNode;
                                } 
                                else
                                { 
                                    prev.m_next = newNode; 
                                }
 
                                return true;
                            }

                            return false; 
                        }
 
                        prev = node; 
                    }
 
                    //didn't find the key
                    return false;
                }
            } 
        }
 
        ///  
        /// Removes all keys and values from the .
        ///  
        public void Clear()
        {
            int locksAcquired = 0;
            try 
            {
                AcquireAllLocks(ref locksAcquired); 
 
                m_buckets = new Node[DEFAULT_CAPACITY];
                Array.Clear(m_countPerLock, 0, m_countPerLock.Length); 
            }
            finally
            {
                ReleaseLocks(0, locksAcquired); 
            }
        } 
 
        /// 
        /// Copies the elements of the  to an array of 
        /// type , starting at the
        /// specified array index.
        /// 
        /// The one-dimensional array of type 
        /// that is the destination of the  elements copied from the . The array must have zero-based indexing.
        /// The zero-based index in  at which copying 
        /// begins.
        ///  is a null reference
        /// (Nothing in Visual Basic).
        ///  is less than 
        /// 0.
        ///  is equal to or greater than 
        /// the length of the . -or- The number of elements in the source 
        /// is greater than the available space from  to the end of the destination 
        /// .
        void ICollection>.CopyTo(KeyValuePair[] array, int index)
        {
            if (array == null) throw new ArgumentNullException("array"); 
            if (index < 0) throw new ArgumentOutOfRangeException("index", GetResource("ConcurrentDictionary_IndexIsNegative"));
 
            int locksAcquired = 0; 
            try
            { 
                AcquireAllLocks(ref locksAcquired);

                int count = 0;
 
                for (int i = 0; i < m_locks.Length; i++)
                { 
                    count += m_countPerLock[i]; 
                }
 
                if (array.Length - count < index || count < 0) //"count" itself or "count + index" can overflow
                {
                    throw new ArgumentException(GetResource("ConcurrentDictionary_ArrayNotLargeEnough"));
                } 

                CopyToPairs(array, index); 
            } 
            finally
            { 
                ReleaseLocks(0, locksAcquired);
            }
        }
 
        /// 
        /// Copies the key and value pairs stored in the  to a 
        /// new array. 
        /// 
        /// A new array containing a snapshot of key and value pairs copied from the .
        public KeyValuePair[] ToArray()
        {
            int locksAcquired = 0; 
            try
            { 
                AcquireAllLocks(ref locksAcquired); 
                int count = 0;
                checked 
                {
                    for (int i = 0; i < m_locks.Length; i++)
                    {
                        count += m_countPerLock[i]; 
                    }
                } 
 
                KeyValuePair[] array = new KeyValuePair[count];
 
                CopyToPairs(array, 0);
                return array;
            }
            finally 
            {
                ReleaseLocks(0, locksAcquired); 
            } 
        }
 
        /// 
        /// Copy dictionary contents to an array - shared implementation between ToArray and CopyTo.
        ///
        /// Important: the caller must hold all locks in m_locks before calling CopyToPairs. 
        /// 
        private void CopyToPairs(KeyValuePair[] array, int index) 
        { 
            Node[] buckets = m_buckets;
            for (int i = 0; i < buckets.Length; i++) 
            {
                for (Node current = buckets[i]; current != null; current = current.m_next)
                {
                    array[index] = new KeyValuePair(current.m_key, current.m_value); 
                    index++; //this should never flow, CopyToPairs is only called when there's no overflow risk
                } 
            } 
        }
 
        /// 
        /// Copy dictionary contents to an array - shared implementation between ToArray and CopyTo.
        ///
        /// Important: the caller must hold all locks in m_locks before calling CopyToEntries. 
        /// 
        private void CopyToEntries(DictionaryEntry[] array, int index) 
        { 
            Node[] buckets = m_buckets;
            for (int i = 0; i < buckets.Length; i++) 
            {
                for (Node current = buckets[i]; current != null; current = current.m_next)
                {
                    array[index] = new DictionaryEntry(current.m_key, current.m_value); 
                    index++;  //this should never flow, CopyToEntries is only called when there's no overflow risk
                } 
            } 
        }
 
        /// 
        /// Copy dictionary contents to an array - shared implementation between ToArray and CopyTo.
        ///
        /// Important: the caller must hold all locks in m_locks before calling CopyToObjects. 
        /// 
        private void CopyToObjects(object[] array, int index) 
        { 
            Node[] buckets = m_buckets;
            for (int i = 0; i < buckets.Length; i++) 
            {
                for (Node current = buckets[i]; current != null; current = current.m_next)
                {
                    array[index] = new KeyValuePair(current.m_key, current.m_value); 
                    index++; //this should never flow, CopyToObjects is only called when there's no overflow risk
                } 
            } 
        }
 
        /// Returns an enumerator that iterates through the .
        /// An enumerator for the .
        ///  
        /// The enumerator returned from the dictionary is safe to use concurrently with
        /// reads and writes to the dictionary, however it does not represent a moment-in-time snapshot 
        /// of the dictionary.  The contents exposed through the enumerator may contain modifications 
        /// made to the dictionary after  was called.
        ///  
        public IEnumerator> GetEnumerator()
        {
            Node[] buckets = m_buckets;
 
            for (int i = 0; i < buckets.Length; i++)
            { 
                Node current = buckets[i]; 

                // The memory barrier ensures that the load of the fields of 'current' doesn’t move before the load from buckets[i]. 
                Thread.MemoryBarrier();
                while (current != null)
                {
                    yield return new KeyValuePair(current.m_key, current.m_value); 
                    current = current.m_next;
                } 
            } 
        }
 
        /// 
        /// Shared internal implementation for inserts and updates.
        /// If key exists, we always return false; and if updateIfExists == true we force update with value;
        /// If key doesn't exist, we always add value and return true; 
        /// 
        private bool TryAddInternal(TKey key, TValue value, bool updateIfExists, bool acquireLock, out TValue resultingValue) 
        { 
            int hashcode = m_comparer.GetHashCode(key);
 
            while (true)
            {
                int bucketNo, lockNo;
 
                Node[] buckets = m_buckets;
                GetBucketAndLockNo(hashcode, out bucketNo, out lockNo, buckets.Length); 
 
                bool resizeDesired = false;
                bool lockTaken = false; 
                try
                {
                    if (acquireLock)
                        Monitor.Enter(m_locks[lockNo], ref lockTaken); 

                    // If the table just got resized, we may not be holding the right lock, and must retry. 
                    // This should be a rare occurence. 
                    if (buckets != m_buckets)
                    { 
                        continue;
                    }

                    // Try to find this key in the bucket 
                    Node prev = null;
                    for (Node node = buckets[bucketNo]; node != null; node = node.m_next) 
                    { 
                        Assert((prev == null && node == m_buckets[bucketNo]) || prev.m_next == node);
                        if (m_comparer.Equals(node.m_key, key)) 
                        {
                            // The key was found in the dictionary. If updates are allowed, update the value for that key.
                            // We need to create a new node for the update, in order to support TValue types that cannot
                            // be written atomically, since lock-free reads may be happening concurrently. 
                            if (updateIfExists)
                            { 
                                Node newNode = new Node(node.m_key, value, hashcode, node.m_next); 
                                if (prev == null)
                                { 
                                    buckets[bucketNo] = newNode;
                                }
                                else
                                { 
                                    prev.m_next = newNode;
                                } 
                                resultingValue = value; 
                            }
                            else 
                            {
                                resultingValue = node.m_value;
                            }
                            return false; 
                        }
                        prev = node; 
                    } 

                    // The key was not found in the bucket. Insert the key-value pair. 
                    buckets[bucketNo] = new Node(key, value, hashcode, buckets[bucketNo]);
                    checked
                    {
                        m_countPerLock[lockNo]++; 
                    }
 
                    // 
                    // If this lock has element / bucket ratio greater than 1, resize the entire table.
                    // Note: the formula is chosen to avoid overflow, but has a small inaccuracy due to 
                    // rounding.
                    //
                    if (m_countPerLock[lockNo] > buckets.Length / m_locks.Length)
                    { 
                        resizeDesired = true;
                    } 
                } 
                finally
                { 
                    if (lockTaken)
                        Monitor.Exit(m_locks[lockNo]);
                }
 
                //
                // The fact that we got here means that we just performed an insertion. If necessary, we will grow the table. 
                // 
                // Concurrency notes:
                // - Notice that we are not holding any locks at when calling GrowTable. This is necessary to prevent deadlocks. 
                // - As a result, it is possible that GrowTable will be called unnecessarily. But, GrowTable will obtain lock 0
                //   and then verify that the table we passed to it as the argument is still the current table.
                //
                if (resizeDesired) 
                {
                    GrowTable(buckets); 
                } 

                resultingValue = value; 
                return true;
            }
        }
 
        /// 
        /// Gets or sets the value associated with the specified key. 
        ///  
        /// The key of the value to get or set.
        /// The value associated with the specified key. If the specified key is not found, a get 
        /// operation throws a
        /// , and a set operation creates a new
        /// element with the specified key.
        ///  is a null reference 
        /// (Nothing in Visual Basic).
        /// The property is retrieved and 
        ///  
        /// does not exist in the collection.
        public TValue this[TKey key] 
        {
            get
            {
                TValue value; 
                if (!TryGetValue(key, out value))
                { 
                    throw new KeyNotFoundException(); 
                }
                return value; 
            }
            set
            {
                if (key == null) throw new ArgumentNullException("key"); 
                TValue dummy;
                TryAddInternal(key, value, true, true, out dummy); 
            } 
        }
 
        /// 
        /// Gets the number of key/value pairs contained in the .
        ///  
        /// The dictionary contains too many
        /// elements. 
        /// The number of key/value paris contained in the .
        /// Count has snapshot semantics and represents the number of items in the 
        /// at the moment when Count was accessed.
        public int Count
        { 
            get
            { 
                int count = 0; 

                int acquiredLocks = 0; 
                try
                {
                    // Acquire all locks
                    AcquireAllLocks(ref acquiredLocks); 

                    // Compute the count, we allow overflow 
                    for (int i = 0; i < m_countPerLock.Length; i++) 
                    {
                        count += m_countPerLock[i]; 
                    }

                }
                finally 
                {
                    // Release locks that have been acquired earlier 
                    ReleaseLocks(0, acquiredLocks); 
                }
 
                return count;
            }
        }
 
        /// 
        /// Adds a key/value pair to the  
        /// if the key does not already exist. 
        /// 
        /// The key of the element to add. 
        /// The function used to generate a value for the key
        ///  is a null reference
        /// (Nothing in Visual Basic).
        ///  is a null reference 
        /// (Nothing in Visual Basic).
        /// The dictionary contains too many 
        /// elements. 
        /// The value for the key.  This will be either the existing value for the key if the
        /// key is already in the dictionary, or the new value for the key as returned by valueFactory 
        /// if the key was not in the dictionary.
        public TValue GetOrAdd(TKey key, Func valueFactory)
        {
            if (key == null) throw new ArgumentNullException("key"); 
            if (valueFactory == null) throw new ArgumentNullException("valueFactory");
 
            TValue resultingValue; 
            if (TryGetValue(key, out resultingValue))
            { 
                return resultingValue;
            }
            TryAddInternal(key, valueFactory(key), false, true, out resultingValue);
            return resultingValue; 
        }
 
        ///  
        /// Adds a key/value pair to the 
        /// if the key does not already exist. 
        /// 
        /// The key of the element to add.
        /// the value to be added, if the key does not already exist
        ///  is a null reference 
        /// (Nothing in Visual Basic).
        /// The dictionary contains too many 
        /// elements. 
        /// The value for the key.  This will be either the existing value for the key if the
        /// key is already in the dictionary, or the new value if the key was not in the dictionary. 
        public TValue GetOrAdd(TKey key, TValue value)
        {
            if (key == null) throw new ArgumentNullException("key");
 
            TValue resultingValue;
            TryAddInternal(key, value, false, true, out resultingValue); 
            return resultingValue; 
        }
 
        /// 
        /// Adds a key/value pair to the  if the key does not already
        /// exist, or updates a key/value pair in the  if the key
        /// already exists. 
        /// 
        /// The key to be added or whose value should be updated 
        /// The function used to generate a value for an absent key 
        /// The function used to generate a new value for an existing key
        /// based on the key's existing value 
        ///  is a null reference
        /// (Nothing in Visual Basic).
        ///  is a null reference
        /// (Nothing in Visual Basic). 
        ///  is a null reference
        /// (Nothing in Visual Basic). 
        /// The dictionary contains too many 
        /// elements.
        /// The new value for the key.  This will be either be the result of addValueFactory (if the key was 
        /// absent) or the result of updateValueFactory (if the key was present).
        public TValue AddOrUpdate(TKey key, Func addValueFactory, Func updateValueFactory)
        {
            if (key == null) throw new ArgumentNullException("key"); 
            if (addValueFactory == null) throw new ArgumentNullException("addValueFactory");
            if (updateValueFactory == null) throw new ArgumentNullException("updateValueFactory"); 
 
            TValue newValue, resultingValue;
            while (true) 
            {
                TValue oldValue;
                if (TryGetValue(key, out oldValue))
                //key exists, try to update 
                {
                    newValue = updateValueFactory(key, oldValue); 
                    if (TryUpdate(key, newValue, oldValue)) 
                    {
                        return newValue; 
                    }
                }
                else //try add
                { 
                    newValue = addValueFactory(key);
                    if (TryAddInternal(key, newValue, false, true, out resultingValue)) 
                    { 
                        return resultingValue;
                    } 
                }
            }
        }
 
        /// 
        /// Adds a key/value pair to the  if the key does not already 
        /// exist, or updates a key/value pair in the  if the key 
        /// already exists.
        ///  
        /// The key to be added or whose value should be updated
        /// The value to be added for an absent key
        /// The function used to generate a new value for an existing key based on
        /// the key's existing value 
        ///  is a null reference
        /// (Nothing in Visual Basic). 
        ///  is a null reference 
        /// (Nothing in Visual Basic).
        /// The dictionary contains too many 
        /// elements.
        /// The new value for the key.  This will be either be the result of addValueFactory (if the key was
        /// absent) or the result of updateValueFactory (if the key was present).
        public TValue AddOrUpdate(TKey key, TValue addValue, Func updateValueFactory) 
        {
            if (key == null) throw new ArgumentNullException("key"); 
            if (updateValueFactory == null) throw new ArgumentNullException("updateValueFactory"); 
            TValue newValue, resultingValue;
            while (true) 
            {
                TValue oldValue;
                if (TryGetValue(key, out oldValue))
                //key exists, try to update 
                {
                    newValue = updateValueFactory(key, oldValue); 
                    if (TryUpdate(key, newValue, oldValue)) 
                    {
                        return newValue; 
                    }
                }
                else //try add
                { 
                    if (TryAddInternal(key, addValue, false, true, out resultingValue))
                    { 
                        return resultingValue; 
                    }
                } 
            }
        }

 

        ///  
        /// Gets a value that indicates whether the  is empty. 
        /// 
        /// true if the  is empty; otherwise, 
        /// false.
        public bool IsEmpty
        {
            get 
            {
                int acquiredLocks = 0; 
                try 
                {
                    // Acquire all locks 
                    AcquireAllLocks(ref acquiredLocks);

                    for (int i = 0; i < m_countPerLock.Length; i++)
                    { 
                        if (m_countPerLock[i] != 0)
                        { 
                            return false; 
                        }
                    } 
                }
                finally
                {
                    // Release locks that have been acquired earlier 
                    ReleaseLocks(0, acquiredLocks);
                } 
 
                return true;
            } 
        }

        #region IDictionary members
 
        /// 
        /// Adds the specified key and value to the . 
        /// 
        /// The object to use as the key of the element to add. 
        /// The object to use as the value of the element to add.
        ///  is a null reference
        /// (Nothing in Visual Basic).
        /// The dictionary contains too many 
        /// elements.
        ///  
        /// An element with the same key already exists in the .
        void IDictionary.Add(TKey key, TValue value) 
        {
            if (!TryAdd(key, value))
            {
                throw new ArgumentException(GetResource("ConcurrentDictionary_KeyAlreadyExisted")); 
            }
        } 
 
        /// 
        /// Removes the element with the specified key from the .
        /// 
        /// The key of the element to remove.
        /// true if the element is successfully remove; otherwise false. This method also returns 
        /// false if
        ///  was not found in the original . 
        /// 
        ///  is a null reference 
        /// (Nothing in Visual Basic).
        bool IDictionary.Remove(TKey key)
        {
            TValue throwAwayValue; 
            return TryRemove(key, out throwAwayValue);
        } 
 
        /// 
        /// Gets a collection containing the keys in the .
        /// 
        /// An  containing the keys in the
        /// . 
        public ICollection Keys
        { 
            get { return GetKeys(); } 
        }
 
        /// 
        /// Gets a collection containing the values in the .
        ///  
        /// An  containing the values in
        /// the 
        /// . 
        public ICollection Values
        { 
            get { return GetValues(); }
        }
        #endregion
 
        #region ICollection> Members
 
        ///  
        /// Adds the specified value to the 
        /// with the specified key. 
        /// 
        /// The 
        /// structure representing the key and value to add to the . 
        /// The  of  is null. 
        /// The 
        /// contains too many elements. 
        /// An element with the same key already exists in the
        /// 
        void ICollection>.Add(KeyValuePair keyValuePair)
        { 
            ((IDictionary)this).Add(keyValuePair.Key, keyValuePair.Value);
        } 
 
        /// 
        /// Determines whether the  
        /// contains a specific key and value.
        /// 
        /// The 
        /// structure to locate in the .
        /// true if the  is found in the ; otherwise, false. 
        bool ICollection>.Contains(KeyValuePair keyValuePair)
        { 
            TValue value;
            if (!TryGetValue(keyValuePair.Key, out value))
            {
                return false; 
            }
            return EqualityComparer.Default.Equals(value, keyValuePair.Value); 
        } 

        ///  
        /// Gets a value indicating whether the dictionary is read-only.
        /// 
        /// true if the  is
        /// read-only; otherwise, false. For , this property always returns
        /// false. 
        bool ICollection>.IsReadOnly 
        {
            get { return false; } 
        }

        /// 
        /// Removes a key and value from the dictionary. 
        /// 
        /// The  
        /// structure representing the key and value to remove from the . 
        /// true if the key and value represented by  is successfully
        /// found and removed; otherwise, false.
        /// The Key property of  is a null reference (Nothing in Visual Basic). 
        bool ICollection>.Remove(KeyValuePair keyValuePair)
        { 
            if (keyValuePair.Key == null) throw new ArgumentNullException(GetResource("ConcurrentDictionary_ItemKeyIsNull")); 

            TValue throwAwayValue; 
            return TryRemoveInternal(keyValuePair.Key, out throwAwayValue, true, keyValuePair.Value);
        }

        #endregion 

        #region IEnumerable Members 
 
        /// Returns an enumerator that iterates through the . 
        /// An enumerator for the .
        /// 
        /// The enumerator returned from the dictionary is safe to use concurrently with
        /// reads and writes to the dictionary, however it does not represent a moment-in-time snapshot 
        /// of the dictionary.  The contents exposed through the enumerator may contain modifications
        /// made to the dictionary after  was called. 
        ///  
        IEnumerator IEnumerable.GetEnumerator()
        { 
            return ((ConcurrentDictionary)this).GetEnumerator();
        }

        #endregion 

        #region IDictionary Members 
 
        /// 
        /// Adds the specified key and value to the dictionary. 
        /// 
        /// The object to use as the key.
        /// The object to use as the value.
        ///  is a null reference 
        /// (Nothing in Visual Basic).
        /// The dictionary contains too many 
        /// elements. 
        /// 
        ///  is of a type that is not assignable to the key type  of the . -or-
        ///  is of a type that is not assignable to ,
        /// the type of values in the .
        /// -or- A value with the same key already exists in the .
        ///  
        void IDictionary.Add(object key, object value) 
        {
            if (key == null) throw new ArgumentNullException("key"); 
            if (!(key is TKey)) throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfKeyIncorrect"));

            TValue typedValue;
            try 
            {
                typedValue = (TValue)value; 
            } 
            catch (InvalidCastException)
            { 
                throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfValueIncorrect"));
            }

            ((IDictionary)this).Add((TKey)key, typedValue); 
        }
 
        ///  
        /// Gets whether the  contains an
        /// element with the specified key. 
        /// 
        /// The key to locate in the .
        /// true if the  contains 
        /// an element with the specified key; otherwise, false.
        ///   is a null reference 
        /// (Nothing in Visual Basic). 
        bool IDictionary.Contains(object key)
        { 
            if (key == null) throw new ArgumentNullException("key");

            return (key is TKey) && ((ConcurrentDictionary)this).ContainsKey((TKey)key);
        } 

        /// Provides an  for the 
        /// . 
        /// An  for the . 
        IDictionaryEnumerator IDictionary.GetEnumerator()
        {
            return new DictionaryEnumerator(this);
        } 

        ///  
        /// Gets a value indicating whether the  has a fixed size.
        ///  
        /// true if the  has a
        /// fixed size; otherwise, false. For , this property always
        /// returns false. 
        bool IDictionary.IsFixedSize
        { 
            get { return false; } 
        }
 
        /// 
        /// Gets a value indicating whether the  is read-only.
        ///  
        /// true if the  is
        /// read-only; otherwise, false. For , this property always 
        /// returns false.
        bool IDictionary.IsReadOnly 
        {
            get { return false; }
        }
 
        /// 
        /// Gets an  containing the keys of the . 
        /// 
        /// An  containing the keys of the .
        ICollection IDictionary.Keys
        {
            get { return GetKeys(); } 
        }
 
        ///  
        /// Removes the element with the specified key from the . 
        /// 
        /// The key of the element to remove.
        ///  is a null reference
        /// (Nothing in Visual Basic). 
        void IDictionary.Remove(object key)
        { 
            if (key == null) throw new ArgumentNullException("key"); 

            TValue throwAwayValue; 
            if (key is TKey)
            {
                this.TryRemove((TKey)key, out throwAwayValue);
            } 
        }
 
        ///  
        /// Gets an  containing the values in the . 
        /// 
        /// An  containing the values in the .
        ICollection IDictionary.Values 
        {
            get { return GetValues(); } 
        } 

        ///  
        /// Gets or sets the value associated with the specified key.
        /// 
        /// The key of the value to get or set.
        /// The value associated with the specified key, or a null reference (Nothing in Visual Basic) 
        /// if  is not in the dictionary or  is of a type that is
        /// not assignable to the key type  of the . 
        ///  is a null reference
        /// (Nothing in Visual Basic). 
        /// 
        /// A value is being assigned, and  is of a type that is not assignable to the
        /// key type  of the . -or- A value is being 
        /// assigned, and  is of a type that is not assignable to the value type
        ///  of the  
        /// 
        object IDictionary.this[object key] 
        {
            get
            {
                if (key == null) throw new ArgumentNullException("key"); 

                TValue value; 
                if (key is TKey && this.TryGetValue((TKey)key, out value)) 
                {
                    return value; 
                }

                return null;
            } 
            set
            { 
                if (key == null) throw new ArgumentNullException("key"); 

                if (!(key is TKey)) throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfKeyIncorrect")); 
                if (!(value is TValue)) throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfValueIncorrect"));

                ((ConcurrentDictionary)this)[(TKey)key] = (TValue)value;
            } 
        }
 
        #endregion 

        #region ICollection Members 

        /// 
        /// Copies the elements of the  to an array, starting
        /// at the specified array index. 
        /// 
        /// The one-dimensional array that is the destination of the elements copied from 
        /// the . The array must have zero-based 
        /// indexing.
        /// The zero-based index in  at which copying 
        /// begins.
        ///  is a null reference
        /// (Nothing in Visual Basic).
        ///  is less than 
        /// 0.
        ///  is equal to or greater than 
        /// the length of the . -or- The number of elements in the source 
        /// is greater than the available space from  to the end of the destination 
        /// .
        void ICollection.CopyTo(Array array, int index)
        {
            if (array == null) throw new ArgumentNullException("array"); 
            if (index < 0) throw new ArgumentOutOfRangeException("index", GetResource("ConcurrentDictionary_IndexIsNegative"));
 
            int locksAcquired = 0; 
            try
            { 
                AcquireAllLocks(ref locksAcquired);

                int count = 0;
 
                for (int i = 0; i < m_locks.Length; i++)
                { 
                    count += m_countPerLock[i]; 
                }
 
                if (array.Length - count < index || count < 0) //"count" itself or "count + index" can overflow
                {
                    throw new ArgumentException(GetResource("ConcurrentDictionary_ArrayNotLargeEnough"));
                } 

                // To be consistent with the behavior of ICollection.CopyTo() in Dictionary, 
                // we recognize three types of target arrays: 
                //    - an array of KeyValuePair structs
                //    - an array of DictionaryEntry structs 
                //    - an array of objects

                KeyValuePair[] pairs = array as KeyValuePair[];
                if (pairs != null) 
                {
                    CopyToPairs(pairs, index); 
                    return; 
                }
 
                DictionaryEntry[] entries = array as DictionaryEntry[];
                if (entries != null)
                {
                    CopyToEntries(entries, index); 
                    return;
                } 
 
                object[] objects = array as object[];
                if (objects != null) 
                {
                    CopyToObjects(objects, index);
                    return;
                } 

                throw new ArgumentException(GetResource("ConcurrentDictionary_ArrayIncorrectType"), "array"); 
            } 
            finally
            { 
                ReleaseLocks(0, locksAcquired);
            }
        }
 
        /// 
        /// Gets a value indicating whether access to the  is 
        /// synchronized with the SyncRoot. 
        /// 
        /// true if access to the  is synchronized 
        /// (thread safe); otherwise, false. For , this property always
        /// returns false.
        bool ICollection.IsSynchronized 
        {
            get { return false; } 
        } 

        ///  
        /// Gets an object that can be used to synchronize access to the . This property is not supported.
        /// 
        /// The SyncRoot property is not supported. 
        object ICollection.SyncRoot
        { 
            get 
            {
                throw new NotSupportedException(Environment.GetResourceString("ConcurrentCollection_SyncRoot_NotSupported")); 
            }
        }

        #endregion 

        ///  
        /// Replaces the internal table with a larger one. To prevent multiple threads from resizing the 
        /// table as a result of ----s, the table of buckets that was deemed too small is passed in as
        /// an argument to GrowTable(). GrowTable() obtains a lock, and then checks whether the bucket 
        /// table has been replaced in the meantime or not.
        /// 
        /// Reference to the bucket table that was deemed too small.
        private void GrowTable(Node[] buckets) 
        {
            int locksAcquired = 0; 
            try 
            {
                // The thread that first obtains m_locks[0] will be the one doing the resize operation 
                AcquireLocks(0, 1, ref locksAcquired);

                // Make sure nobody resized the table while we were waiting for lock 0:
                if (buckets != m_buckets) 
                {
                    // We assume that since the table reference is different, it was already resized. If we ever 
                    // decide to do table shrinking, or replace the table for other reasons, we will have to revisit 
                    // this logic.
                    return; 
                }

                // Compute the new table size. We find the smallest integer larger than twice the previous table size, and not divisible by
                // 2,3,5 or 7. We can consider a different table-sizing policy in the future. 
                int newLength;
                try 
                { 
                    checked
                    { 
                        // Double the size of the buckets table and add one, so that we have an odd integer.
                        newLength = buckets.Length * 2 + 1;

                        // Now, we only need to check odd integers, and find the first that is not divisible 
                        // by 3, 5 or 7.
                        while (newLength % 3 == 0 || newLength % 5 == 0 || newLength % 7 == 0) 
                        { 
                            newLength += 2;
                        } 

                        Assert(newLength % 2 != 0);
                    }
                } 
                catch (OverflowException)
                { 
                    // If we were to resize the table, its new size will not fit into a 32-bit signed int. Just return. 
                    return;
                } 

                Node[] newBuckets = new Node[newLength];
                int[] newCountPerLock = new int[m_locks.Length];
 
                // Now acquire all other locks for the table
                AcquireLocks(1, m_locks.Length, ref locksAcquired); 
 
                // Copy all data into a new table, creating new nodes for all elements
                for (int i = 0; i < buckets.Length; i++) 
                {
                    Node current = buckets[i];
                    while (current != null)
                    { 
                        Node next = current.m_next;
                        int newBucketNo, newLockNo; 
                        GetBucketAndLockNo(current.m_hashcode, out newBucketNo, out newLockNo, newBuckets.Length); 

                        newBuckets[newBucketNo] = new Node(current.m_key, current.m_value, current.m_hashcode, newBuckets[newBucketNo]); 

                        checked
                        {
                            newCountPerLock[newLockNo]++; 
                        }
 
                        current = next; 
                    }
                } 

                // And finally adjust m_buckets and m_countPerLock to point to data for the new table
                m_buckets = newBuckets;
                m_countPerLock = newCountPerLock; 

            } 
            finally 
            {
                // Release all locks that we took earlier 
                ReleaseLocks(0, locksAcquired);
            }
        }
 
        /// 
        /// Computes the bucket and lock number for a particular key. 
        ///  
        private void GetBucketAndLockNo(
                int hashcode, out int bucketNo, out int lockNo, int bucketCount) 
        {
            bucketNo = (hashcode & 0x7fffffff) % bucketCount;
            lockNo = bucketNo % m_locks.Length;
 
            Assert(bucketNo >= 0 && bucketNo < bucketCount);
            Assert(lockNo >= 0 && lockNo < m_locks.Length); 
        } 

        ///  
        /// The number of concurrent writes for which to optimize by default.
        /// 
        private static int DefaultConcurrencyLevel
        { 

            get { return DEFAULT_CONCURRENCY_MULTIPLIER * Environment.ProcessorCount; } 
        } 

        ///  
        /// Acquires all locks for this hash table, and increments locksAcquired by the number
        /// of locks that were successfully acquired. The locks are acquired in an increasing
        /// order.
        ///  
        private void AcquireAllLocks(ref int locksAcquired)
        { 
#if !FEATURE_PAL 
            if (CDSCollectionETWBCLProvider.Log.IsEnabled())
            { 
                CDSCollectionETWBCLProvider.Log.ConcurrentDictionary_AcquiringAllLocks(m_buckets.Length);
            }
#endif //!FEATURE_PAL
 
            AcquireLocks(0, m_locks.Length, ref locksAcquired);
            Assert(locksAcquired == m_locks.Length); 
        } 

        ///  
        /// Acquires a contiguous range of locks for this hash table, and increments locksAcquired
        /// by the number of locks that were successfully acquired. The locks are acquired in an
        /// increasing order.
        ///  
        private void AcquireLocks(int fromInclusive, int toExclusive, ref int locksAcquired)
        { 
            Assert(fromInclusive <= toExclusive); 

            for (int i = fromInclusive; i < toExclusive; i++) 
            {
                bool lockTaken = false;
                try
                { 
#if CDS_COMPILE_JUST_THIS
                    Monitor.Enter(m_locks[i]); 
                    lockTaken = true; 
#else
                    Monitor.Enter(m_locks[i], ref lockTaken); 
#endif
                }
                finally
                { 
                    if (lockTaken)
                    { 
                        locksAcquired++; 
                    }
                } 
            }
        }

        ///  
        /// Releases a contiguous range of locks.
        ///  
        private void ReleaseLocks(int fromInclusive, int toExclusive) 
        {
            Assert(fromInclusive <= toExclusive); 

            for (int i = fromInclusive; i < toExclusive; i++)
            {
                Monitor.Exit(m_locks[i]); 
            }
        } 
 
        /// 
        /// Gets a collection containing the keys in the dictionary. 
        /// 
        private ReadOnlyCollection GetKeys()
        {
            int locksAcquired = 0; 
            try
            { 
                AcquireAllLocks(ref locksAcquired); 
                List keys = new List();
 
                for (int i = 0; i < m_buckets.Length; i++)
                {
                    Node current = m_buckets[i];
                    while (current != null) 
                    {
                        keys.Add(current.m_key); 
                        current = current.m_next; 
                    }
                } 

                return new ReadOnlyCollection(keys);
            }
            finally 
            {
                ReleaseLocks(0, locksAcquired); 
            } 
        }
 
        /// 
        /// Gets a collection containing the values in the dictionary.
        /// 
        private ReadOnlyCollection GetValues() 
        {
            int locksAcquired = 0; 
            try 
            {
                AcquireAllLocks(ref locksAcquired); 
                List values = new List();

                for (int i = 0; i < m_buckets.Length; i++)
                { 
                    Node current = m_buckets[i];
                    while (current != null) 
                    { 
                        values.Add(current.m_value);
                        current = current.m_next; 
                    }
                }

                return new ReadOnlyCollection(values); 
            }
            finally 
            { 
                ReleaseLocks(0, locksAcquired);
            } 
        }

        /// 
        /// A helper method for asserts. 
        /// 
        [Conditional("DEBUG")] 
        private void Assert(bool condition) 
        {
#if CDS_COMPILE_JUST_THIS 
            if (!condition)
            {
                throw new Exception("Assertion failed.");
            } 
#else
            Contract.Assert(condition); 
#endif 
        }
 
        /// 
        /// A helper function to obtain the string for a particular resource key.
        /// 
        ///  
        /// 
        private string GetResource(string key) 
        { 
            Assert(key != null);
 
#if CDS_COMPILE_JUST_THIS
            return key;
#else
            return Environment.GetResourceString(key); 
#endif
        } 
 
        /// 
        /// A node in a singly-linked list representing a particular hash table bucket. 
        /// 
        private class Node
        {
            internal TKey m_key; 
            internal TValue m_value;
            internal volatile Node m_next; 
            internal int m_hashcode; 

            internal Node(TKey key, TValue value, int hashcode) 
                : this(key, value, hashcode, null)
            {
            }
 
            internal Node(TKey key, TValue value, int hashcode, Node next)
            { 
                m_key = key; 
                m_value = value;
                m_next = next; 
                m_hashcode = hashcode;
            }
        }
 
        /// 
        /// A private class to represent enumeration over the dictionary that implements the 
        /// IDictionaryEnumerator interface. 
        /// 
        private class DictionaryEnumerator : IDictionaryEnumerator 
        {
            IEnumerator> m_enumerator; // Enumerator over the dictionary.

            internal DictionaryEnumerator(ConcurrentDictionary dictionary) 
            {
                m_enumerator = dictionary.GetEnumerator(); 
            } 

            public DictionaryEntry Entry 
            {
                get { return new DictionaryEntry(m_enumerator.Current.Key, m_enumerator.Current.Value); }
            }
 
            public object Key
            { 
                get { return m_enumerator.Current.Key; } 
            }
 
            public object Value
            {
                get { return m_enumerator.Current.Value; }
            } 

            public object Current 
            { 
                get { return this.Entry; }
            } 

            public bool MoveNext()
            {
                return m_enumerator.MoveNext(); 
            }
 
            public void Reset() 
            {
                m_enumerator.Reset(); 
            }
        }

        ///  
        /// Get the data array to be serialized
        ///  
        [OnSerializing] 
        private void OnSerializing(StreamingContext context)
        { 
            // save the data into the serialization array to be saved
            m_serializationArray = ToArray();
            m_serializationConcurrencyLevel = m_locks.Length;
            m_serializationCapacity = m_buckets.Length; 
        }
 
        ///  
        /// Construct the dictionary from a previously seiralized one
        ///  
        [OnDeserialized]
        private void OnDeserialized(StreamingContext context)
        {
            KeyValuePair[] array = m_serializationArray; 

            m_buckets = new Node[m_serializationCapacity]; 
            m_countPerLock = new int[m_serializationConcurrencyLevel]; 

            m_locks = new object[m_serializationConcurrencyLevel]; 
            for (int i = 0; i < m_locks.Length; i++)
            {
                m_locks[i] = new object();
            } 

            InitializeFromCollection(array); 
            m_serializationArray = null; 

        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK