• C#之Dictionary源码


    // ==++==
    // 
    //   Copyright (c) Microsoft Corporation.  All rights reserved.
    // 
    // ==--==
    /*============================================================
    **
    ** Class:  Dictionary
    ** 
    ** <OWNER>Microsoft</OWNER>
    **
    ** Purpose: Generic hash table implementation
    **
    ** #DictionaryVersusHashtableThreadSafety
    ** Hashtable has multiple reader/single writer (MR/SW) thread safety built into 
    ** certain methods and properties, whereas Dictionary doesn't. If you're 
    ** converting framework code that formerly used Hashtable to Dictionary, it's
    ** important to consider whether callers may have taken a dependence on MR/SW
    ** thread safety. If a reader writer lock is available, then that may be used
    ** with a Dictionary to get the same thread safety guarantee. 
    ** 
    ** Reader writer locks don't exist in silverlight, so we do the following as a
    ** result of removing non-generic collections from silverlight: 
    ** 1. If the Hashtable was fully synchronized, then we replace it with a 
    **    Dictionary with full locks around reads/writes (same thread safety
    **    guarantee).
    ** 2. Otherwise, the Hashtable has the default MR/SW thread safety behavior, 
    **    so we do one of the following on a case-by-case basis:
    **    a. If the ---- can be addressed by rearranging the code and using a temp
    **       variable (for example, it's only populated immediately after created)
    **       then we address the ---- this way and use Dictionary.
    **    b. If there's concern about degrading performance with the increased 
    **       locking, we ifdef with FEATURE_NONGENERIC_COLLECTIONS so we can at 
    **       least use Hashtable in the desktop build, but Dictionary with full 
    **       locks in silverlight builds. Note that this is heavier locking than 
    **       MR/SW, but this is the only option without rewriting (or adding back)
    **       the reader writer lock. 
    **    c. If there's no performance concern (e.g. debug-only code) we 
    **       consistently replace Hashtable with Dictionary plus full locks to 
    **       reduce complexity.
    **    d. Most of serialization is dead code in silverlight. Instead of updating
    **       those Hashtable occurences in serialization, we carved out references 
    **       to serialization such that this code doesn't need to build in 
    **       silverlight. 
    ===========================================================*/
    namespace System.Collections.Generic {
     
        using System;
        using System.Collections;
        using System.Diagnostics;
        using System.Diagnostics.Contracts;
        using System.Runtime.Serialization;
        using System.Security.Permissions;
     
        [DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<,>))]
        [DebuggerDisplay("Count = {Count}")]
        [Serializable]
        [System.Runtime.InteropServices.ComVisible(false)]
        public class Dictionary<TKey,TValue>: IDictionary<TKey,TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue>, ISerializable, IDeserializationCallback  {
        
            private struct Entry {
                public int hashCode;    // Lower 31 bits of hash code, -1 if unused
                public int next;        // Index of next entry, -1 if last
                public TKey key;           // Key of entry
                public TValue value;         // Value of entry
            }
     
            private int[] buckets;
            private Entry[] entries;
            private int count;
            private int version;
            private int freeList;
            private int freeCount;
            private IEqualityComparer<TKey> comparer;
            private KeyCollection keys;
            private ValueCollection values;
            private Object _syncRoot;
            
            // constants for serialization
            private const String VersionName = "Version";
            private const String HashSizeName = "HashSize";  // Must save buckets.Length
            private const String KeyValuePairsName = "KeyValuePairs";
            private const String ComparerName = "Comparer";
     
            public Dictionary(): this(0, null) {}
     
            public Dictionary(int capacity): this(capacity, null) {}
     
            public Dictionary(IEqualityComparer<TKey> comparer): this(0, comparer) {}
     
            public Dictionary(int capacity, IEqualityComparer<TKey> comparer) {
                if (capacity < 0) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity);
                if (capacity > 0) Initialize(capacity);
                this.comparer = comparer ?? EqualityComparer<TKey>.Default;
     
    #if FEATURE_CORECLR
                if (HashHelpers.s_UseRandomizedStringHashing && comparer == EqualityComparer<string>.Default)
                {
                    this.comparer = (IEqualityComparer<TKey>) NonRandomizedStringEqualityComparer.Default;
                }
    #endif // FEATURE_CORECLR
            }
     
            public Dictionary(IDictionary<TKey,TValue> dictionary): this(dictionary, null) {}
     
            public Dictionary(IDictionary<TKey,TValue> dictionary, IEqualityComparer<TKey> comparer):
                this(dictionary != null? dictionary.Count: 0, comparer) {
     
                if( dictionary == null) {
                    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary);
                }
     
                foreach (KeyValuePair<TKey,TValue> pair in dictionary) {
                    Add(pair.Key, pair.Value);
                }
            }
     
            protected Dictionary(SerializationInfo info, StreamingContext context) {
                //We can't do anything with the keys and values until the entire graph has been deserialized
                //and we have a resonable estimate that GetHashCode is not going to fail.  For the time being,
                //we'll just cache this.  The graph is not valid until OnDeserialization has been called.
                HashHelpers.SerializationInfoTable.Add(this, info);
            }
                
            public IEqualityComparer<TKey> Comparer {
                get {
                    return comparer;                
                }               
            }
            
            public int Count {
                get { return count - freeCount; }
            }
     
            public KeyCollection Keys {
                get {
                    Contract.Ensures(Contract.Result<KeyCollection>() != null);
                    if (keys == null) keys = new KeyCollection(this);
                    return keys;
                }
            }
     
            ICollection<TKey> IDictionary<TKey, TValue>.Keys {
                get {                
                    if (keys == null) keys = new KeyCollection(this);                
                    return keys;
                }
            }
     
            IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys {
                get {                
                    if (keys == null) keys = new KeyCollection(this);                
                    return keys;
                }
            }
     
            public ValueCollection Values {
                get {
                    Contract.Ensures(Contract.Result<ValueCollection>() != null);
                    if (values == null) values = new ValueCollection(this);
                    return values;
                }
            }
     
            ICollection<TValue> IDictionary<TKey, TValue>.Values {
                get {                
                    if (values == null) values = new ValueCollection(this);
                    return values;
                }
            }
     
            IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values {
                get {                
                    if (values == null) values = new ValueCollection(this);
                    return values;
                }
            }
     
            public TValue this[TKey key] {
                get {
                    int i = FindEntry(key);
                    if (i >= 0) return entries[i].value;
                    ThrowHelper.ThrowKeyNotFoundException();
                    return default(TValue);
                }
                set {
                    Insert(key, value, false);
                }
            }
     
            public void Add(TKey key, TValue value) {
                Insert(key, value, true);
            }
     
            void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> keyValuePair) {
                Add(keyValuePair.Key, keyValuePair.Value);
            }
     
            bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> keyValuePair) {
                int i = FindEntry(keyValuePair.Key);
                if( i >= 0 && EqualityComparer<TValue>.Default.Equals(entries[i].value, keyValuePair.Value)) {
                    return true;
                }
                return false;
            }
     
            bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> keyValuePair) {
                int i = FindEntry(keyValuePair.Key);
                if( i >= 0 && EqualityComparer<TValue>.Default.Equals(entries[i].value, keyValuePair.Value)) {
                    Remove(keyValuePair.Key);
                    return true;
                }
                return false;
            }
     
            public void Clear() {
                if (count > 0) {
                    for (int i = 0; i < buckets.Length; i++) buckets[i] = -1;
                    Array.Clear(entries, 0, count);
                    freeList = -1;
                    count = 0;
                    freeCount = 0;
                    version++;
                }
            }
     
            public bool ContainsKey(TKey key) {
                return FindEntry(key) >= 0;
            }
     
            public bool ContainsValue(TValue value) {
                if (value == null) {
                    for (int i = 0; i < count; i++) {
                        if (entries[i].hashCode >= 0 && entries[i].value == null) return true;
                    }
                }
                else {
                    EqualityComparer<TValue> c = EqualityComparer<TValue>.Default;
                    for (int i = 0; i < count; i++) {
                        if (entries[i].hashCode >= 0 && c.Equals(entries[i].value, value)) return true;
                    }
                }
                return false;
            }
     
            private void CopyTo(KeyValuePair<TKey,TValue>[] array, int index) {
                if (array == null) {
                    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
                }
                
                if (index < 0 || index > array.Length ) {
                    ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
                }
     
                if (array.Length - index < Count) {
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
                }
     
                int count = this.count;
                Entry[] entries = this.entries;
                for (int i = 0; i < count; i++) {
                    if (entries[i].hashCode >= 0) {
                        array[index++] = new KeyValuePair<TKey,TValue>(entries[i].key, entries[i].value);
                    }
                }
            }
     
            public Enumerator GetEnumerator() {
                return new Enumerator(this, Enumerator.KeyValuePair);
            }
     
            IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() {
                return new Enumerator(this, Enumerator.KeyValuePair);
            }        
     
            [System.Security.SecurityCritical]  // auto-generated_required
            public virtual void GetObjectData(SerializationInfo info, StreamingContext context) {
                if (info==null) {
                    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.info);
                }
                info.AddValue(VersionName, version);
     
    #if FEATURE_RANDOMIZED_STRING_HASHING
                info.AddValue(ComparerName, HashHelpers.GetEqualityComparerForSerialization(comparer), typeof(IEqualityComparer<TKey>));
    #else
                info.AddValue(ComparerName, comparer, typeof(IEqualityComparer<TKey>));
    #endif
     
                info.AddValue(HashSizeName, buckets == null ? 0 : buckets.Length); //This is the length of the bucket array.
                if( buckets != null) {
                    KeyValuePair<TKey, TValue>[] array = new KeyValuePair<TKey, TValue>[Count];
                    CopyTo(array, 0);
                    info.AddValue(KeyValuePairsName, array, typeof(KeyValuePair<TKey, TValue>[]));
                }
            }
     
            private int FindEntry(TKey key) {
                if( key == null) {
                    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
                }
     
                if (buckets != null) {
                    int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
                    for (int i = buckets[hashCode % buckets.Length]; i >= 0; i = entries[i].next) {
                        if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) return i;
                    }
                }
                return -1;
            }
     
            private void Initialize(int capacity) {
                int size = HashHelpers.GetPrime(capacity);
                buckets = new int[size];
                for (int i = 0; i < buckets.Length; i++) buckets[i] = -1;
                entries = new Entry[size];
                freeList = -1;
            }
     
            private void Insert(TKey key, TValue value, bool add) {
            
                if( key == null ) {
                    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
                }
     
                if (buckets == null) Initialize(0);
                int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
                int targetBucket = hashCode % buckets.Length;
     
    #if FEATURE_RANDOMIZED_STRING_HASHING
                int collisionCount = 0;
    #endif
     
                for (int i = buckets[targetBucket]; i >= 0; i = entries[i].next) {
                    if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) {
                        if (add) { 
                            ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
                        }
                        entries[i].value = value;
                        version++;
                        return;
                    } 
     
    #if FEATURE_RANDOMIZED_STRING_HASHING
                    collisionCount++;
    #endif
                }
                int index;
                if (freeCount > 0) {
                    index = freeList;
                    freeList = entries[index].next;
                    freeCount--;
                }
                else {
                    if (count == entries.Length)
                    {
                        Resize();
                        targetBucket = hashCode % buckets.Length;
                    }
                    index = count;
                    count++;
                }
     
                entries[index].hashCode = hashCode;
                entries[index].next = buckets[targetBucket];
                entries[index].key = key;
                entries[index].value = value;
                buckets[targetBucket] = index;
                version++;
     
    #if FEATURE_RANDOMIZED_STRING_HASHING
     
    #if FEATURE_CORECLR
                // In case we hit the collision threshold we'll need to switch to the comparer which is using randomized string hashing
                // in this case will be EqualityComparer<string>.Default.
                // Note, randomized string hashing is turned on by default on coreclr so EqualityComparer<string>.Default will 
                // be using randomized string hashing
     
                if (collisionCount > HashHelpers.HashCollisionThreshold && comparer == NonRandomizedStringEqualityComparer.Default) 
                {
                    comparer = (IEqualityComparer<TKey>) EqualityComparer<string>.Default;
                    Resize(entries.Length, true);
                }
    #else
                if(collisionCount > HashHelpers.HashCollisionThreshold && HashHelpers.IsWellKnownEqualityComparer(comparer)) 
                {
                    comparer = (IEqualityComparer<TKey>) HashHelpers.GetRandomizedEqualityComparer(comparer);
                    Resize(entries.Length, true);
                }
    #endif // FEATURE_CORECLR
     
    #endif
     
            }
     
            public virtual void OnDeserialization(Object sender) {
                SerializationInfo siInfo;
                HashHelpers.SerializationInfoTable.TryGetValue(this, out siInfo);
                
                if (siInfo==null) {
                    // It might be necessary to call OnDeserialization from a container if the container object also implements
                    // OnDeserialization. However, remoting will call OnDeserialization again.
                    // We can return immediately if this function is called twice. 
                    // Note we set remove the serialization info from the table at the end of this method.
                    return;
                }            
                
                int realVersion = siInfo.GetInt32(VersionName);
                int hashsize = siInfo.GetInt32(HashSizeName);
                comparer   = (IEqualityComparer<TKey>)siInfo.GetValue(ComparerName, typeof(IEqualityComparer<TKey>));
                
                if( hashsize != 0) {
                    buckets = new int[hashsize];
                    for (int i = 0; i < buckets.Length; i++) buckets[i] = -1;
                    entries = new Entry[hashsize];
                    freeList = -1;
     
                    KeyValuePair<TKey, TValue>[] array = (KeyValuePair<TKey, TValue>[]) 
                        siInfo.GetValue(KeyValuePairsName, typeof(KeyValuePair<TKey, TValue>[]));
     
                    if (array==null) {
                        ThrowHelper.ThrowSerializationException(ExceptionResource.Serialization_MissingKeys);
                    }
     
                    for (int i=0; i<array.Length; i++) {
                        if ( array[i].Key == null) {
                            ThrowHelper.ThrowSerializationException(ExceptionResource.Serialization_NullKey);
                        }
                        Insert(array[i].Key, array[i].Value, true);
                    }
                }
                else {
                    buckets = null;
                }
     
                version = realVersion;
                HashHelpers.SerializationInfoTable.Remove(this);
            }
     
            private void Resize() {
                Resize(HashHelpers.ExpandPrime(count), false);
            }
     
            private void Resize(int newSize, bool forceNewHashCodes) {
                Contract.Assert(newSize >= entries.Length);
                int[] newBuckets = new int[newSize];
                for (int i = 0; i < newBuckets.Length; i++) newBuckets[i] = -1;
                Entry[] newEntries = new Entry[newSize];
                Array.Copy(entries, 0, newEntries, 0, count);
                if(forceNewHashCodes) {
                    for (int i = 0; i < count; i++) {
                        if(newEntries[i].hashCode != -1) {
                            newEntries[i].hashCode = (comparer.GetHashCode(newEntries[i].key) & 0x7FFFFFFF);
                        }
                    }
                }
                for (int i = 0; i < count; i++) {
                    if (newEntries[i].hashCode >= 0) {
                        int bucket = newEntries[i].hashCode % newSize;
                        newEntries[i].next = newBuckets[bucket];
                        newBuckets[bucket] = i;
                    }
                }
                buckets = newBuckets;
                entries = newEntries;
            }
     
            public bool Remove(TKey key) {
                if(key == null) {
                    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
                }
     
                if (buckets != null) {
                    int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
                    int bucket = hashCode % buckets.Length;
                    int last = -1;
                    for (int i = buckets[bucket]; i >= 0; last = i, i = entries[i].next) {
                        if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) {
                            if (last < 0) {
                                buckets[bucket] = entries[i].next;
                            }
                            else {
                                entries[last].next = entries[i].next;
                            }
                            entries[i].hashCode = -1;
                            entries[i].next = freeList;
                            entries[i].key = default(TKey);
                            entries[i].value = default(TValue);
                            freeList = i;
                            freeCount++;
                            version++;
                            return true;
                        }
                    }
                }
                return false;
            }
     
            public bool TryGetValue(TKey key, out TValue value) {
                int i = FindEntry(key);
                if (i >= 0) {
                    value = entries[i].value;
                    return true;
                }
                value = default(TValue);
                return false;
            }
     
            // This is a convenience method for the internal callers that were converted from using Hashtable.
            // Many were combining key doesn't exist and key exists but null value (for non-value types) checks.
            // This allows them to continue getting that behavior with minimal code delta. This is basically
            // TryGetValue without the out param
            internal TValue GetValueOrDefault(TKey key) {
                int i = FindEntry(key);
                if (i >= 0) {
                    return entries[i].value;
                }
                return default(TValue);
            }
     
            bool ICollection<KeyValuePair<TKey,TValue>>.IsReadOnly {
                get { return false; }
            }
     
            void ICollection<KeyValuePair<TKey,TValue>>.CopyTo(KeyValuePair<TKey,TValue>[] array, int index) {
                CopyTo(array, index);
            }
     
            void ICollection.CopyTo(Array array, int index) {
                if (array == null) {
                    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
                }
                
                if (array.Rank != 1) {
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
                }
     
                if( array.GetLowerBound(0) != 0 ) {
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound);
                }
                
                if (index < 0 || index > array.Length) {
                    ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
                }
     
                if (array.Length - index < Count) {
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
                }
                
                KeyValuePair<TKey,TValue>[] pairs = array as KeyValuePair<TKey,TValue>[];
                if (pairs != null) {
                    CopyTo(pairs, index);
                }
                else if( array is DictionaryEntry[]) {
                    DictionaryEntry[] dictEntryArray = array as DictionaryEntry[];
                    Entry[] entries = this.entries;
                    for (int i = 0; i < count; i++) {
                        if (entries[i].hashCode >= 0) {
                            dictEntryArray[index++] = new DictionaryEntry(entries[i].key, entries[i].value);
                        }
                    }                
                }
                else {
                    object[] objects = array as object[];
                    if (objects == null) {
                        ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
                    }
     
                    try {
                        int count = this.count;
                        Entry[] entries = this.entries;
                        for (int i = 0; i < count; i++) {
                            if (entries[i].hashCode >= 0) {
                                objects[index++] = new KeyValuePair<TKey,TValue>(entries[i].key, entries[i].value);
                            }
                        }
                    }
                    catch(ArrayTypeMismatchException) {
                        ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
                    }
                }
            }
     
            IEnumerator IEnumerable.GetEnumerator() {
                return new Enumerator(this, Enumerator.KeyValuePair);
            }
        
            bool ICollection.IsSynchronized {
                get { return false; }
            }
     
            object ICollection.SyncRoot { 
                get { 
                    if( _syncRoot == null) {
                        System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null);    
                    }
                    return _syncRoot; 
                }
            }
     
            bool IDictionary.IsFixedSize {
                get { return false; }
            }
     
            bool IDictionary.IsReadOnly {
                get { return false; }
            }
     
            ICollection IDictionary.Keys {
                get { return (ICollection)Keys; }
            }
        
            ICollection IDictionary.Values {
                get { return (ICollection)Values; }
            }
        
            object IDictionary.this[object key] {
                get { 
                    if( IsCompatibleKey(key)) {                
                        int i = FindEntry((TKey)key);
                        if (i >= 0) { 
                            return entries[i].value;                
                        }
                    }
                    return null;
                }
                set {                 
                    if (key == null)
                    {
                        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);                          
                    }
                    ThrowHelper.IfNullAndNullsAreIllegalThenThrow<TValue>(value, ExceptionArgument.value);
     
                    try {
                        TKey tempKey = (TKey)key;
                        try {
                            this[tempKey] = (TValue)value; 
                        }
                        catch (InvalidCastException) { 
                            ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(TValue));   
                        }
                    }
                    catch (InvalidCastException) { 
                        ThrowHelper.ThrowWrongKeyTypeArgumentException(key, typeof(TKey));
                    }
                }
            }
     
            private static bool IsCompatibleKey(object key) {
                if( key == null) {
                        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);                          
                    }
                return (key is TKey); 
            }
        
            void IDictionary.Add(object key, object value) {            
                if (key == null)
                {
                    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);                          
                }
                ThrowHelper.IfNullAndNullsAreIllegalThenThrow<TValue>(value, ExceptionArgument.value);
     
                try {
                    TKey tempKey = (TKey)key;
     
                    try {
                        Add(tempKey, (TValue)value);
                    }
                    catch (InvalidCastException) { 
                        ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(TValue));   
                    }
                }
                catch (InvalidCastException) { 
                    ThrowHelper.ThrowWrongKeyTypeArgumentException(key, typeof(TKey));
                }
            }
        
            bool IDictionary.Contains(object key) {    
                if(IsCompatibleKey(key)) {
                    return ContainsKey((TKey)key);
                }
           
                return false;
            }
        
            IDictionaryEnumerator IDictionary.GetEnumerator() {
                return new Enumerator(this, Enumerator.DictEntry);
            }
        
            void IDictionary.Remove(object key) {            
                if(IsCompatibleKey(key)) {
                    Remove((TKey)key);
                }
            }
     
            [Serializable]
            public struct Enumerator: IEnumerator<KeyValuePair<TKey,TValue>>,
                IDictionaryEnumerator
            {
                private Dictionary<TKey,TValue> dictionary;
                private int version;
                private int index;
                private KeyValuePair<TKey,TValue> current;
                private int getEnumeratorRetType;  // What should Enumerator.Current return?
                
                internal const int DictEntry = 1;
                internal const int KeyValuePair = 2;
     
                internal Enumerator(Dictionary<TKey,TValue> dictionary, int getEnumeratorRetType) {
                    this.dictionary = dictionary;
                    version = dictionary.version;
                    index = 0;
                    this.getEnumeratorRetType = getEnumeratorRetType;
                    current = new KeyValuePair<TKey, TValue>();
                }
     
                public bool MoveNext() {
                    if (version != dictionary.version) {
                        ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
                    }
     
                    // Use unsigned comparison since we set index to dictionary.count+1 when the enumeration ends.
                    // dictionary.count+1 could be negative if dictionary.count is Int32.MaxValue
                    while ((uint)index < (uint)dictionary.count) {
                        if (dictionary.entries[index].hashCode >= 0) {
                            current = new KeyValuePair<TKey, TValue>(dictionary.entries[index].key, dictionary.entries[index].value);
                            index++;
                            return true;
                        }
                        index++;
                    }
     
                    index = dictionary.count + 1;
                    current = new KeyValuePair<TKey, TValue>();
                    return false;
                }
     
                public KeyValuePair<TKey,TValue> Current {
                    get { return current; }
                }
     
                public void Dispose() {
                }
     
                object IEnumerator.Current {
                    get { 
                        if( index == 0 || (index == dictionary.count + 1)) {
                            ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);                        
                        }      
     
                        if (getEnumeratorRetType == DictEntry) {
                            return new System.Collections.DictionaryEntry(current.Key, current.Value);
                        } else {
                            return new KeyValuePair<TKey, TValue>(current.Key, current.Value);
                        }
                    }
                }
     
                void IEnumerator.Reset() {
                    if (version != dictionary.version) {
                        ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
                    }
     
                    index = 0;
                    current = new KeyValuePair<TKey, TValue>();    
                }
     
                DictionaryEntry IDictionaryEnumerator.Entry {
                    get { 
                        if( index == 0 || (index == dictionary.count + 1)) {
                             ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);                        
                        }                        
                        
                        return new DictionaryEntry(current.Key, current.Value); 
                    }
                }
     
                object IDictionaryEnumerator.Key {
                    get { 
                        if( index == 0 || (index == dictionary.count + 1)) {
                             ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);                        
                        }                        
                        
                        return current.Key; 
                    }
                }
     
                object IDictionaryEnumerator.Value {
                    get { 
                        if( index == 0 || (index == dictionary.count + 1)) {
                             ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);                        
                        }                        
                        
                        return current.Value; 
                    }
                }
            }
     
            [DebuggerTypeProxy(typeof(Mscorlib_DictionaryKeyCollectionDebugView<,>))]
            [DebuggerDisplay("Count = {Count}")]        
            [Serializable]
            public sealed class KeyCollection: ICollection<TKey>, ICollection, IReadOnlyCollection<TKey>
            {
                private Dictionary<TKey,TValue> dictionary;
     
                public KeyCollection(Dictionary<TKey,TValue> dictionary) {
                    if (dictionary == null) {
                        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary);
                    }
                    this.dictionary = dictionary;
                }
     
                public Enumerator GetEnumerator() {
                    return new Enumerator(dictionary);
                }
     
                public void CopyTo(TKey[] array, int index) {
                    if (array == null) {
                        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
                    }
     
                    if (index < 0 || index > array.Length) {
                        ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
                    }
     
                    if (array.Length - index < dictionary.Count) {
                        ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
                    }
                    
                    int count = dictionary.count;
                    Entry[] entries = dictionary.entries;
                    for (int i = 0; i < count; i++) {
                        if (entries[i].hashCode >= 0) array[index++] = entries[i].key;
                    }
                }
     
                public int Count {
                    get { return dictionary.Count; }
                }
     
                bool ICollection<TKey>.IsReadOnly {
                    get { return true; }
                }
     
                void ICollection<TKey>.Add(TKey item){
                    ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_KeyCollectionSet);
                }
                
                void ICollection<TKey>.Clear(){
                    ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_KeyCollectionSet);
                }
     
                bool ICollection<TKey>.Contains(TKey item){
                    return dictionary.ContainsKey(item);
                }
     
                bool ICollection<TKey>.Remove(TKey item){
                    ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_KeyCollectionSet);
                    return false;
                }
                
                IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator() {
                    return new Enumerator(dictionary);
                }
     
                IEnumerator IEnumerable.GetEnumerator() {
                    return new Enumerator(dictionary);                
                }
     
                void ICollection.CopyTo(Array array, int index) {
                    if (array==null) {
                        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
                    }
     
                    if (array.Rank != 1) {
                        ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
                    }
     
                    if( array.GetLowerBound(0) != 0 ) {
                        ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound);
                    }
     
                    if (index < 0 || index > array.Length) {
                        ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
                    }
     
                    if (array.Length - index < dictionary.Count) {
                        ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
                    }
                    
                    TKey[] keys = array as TKey[];
                    if (keys != null) {
                        CopyTo(keys, index);
                    }
                    else {
                        object[] objects = array as object[];
                        if (objects == null) {
                            ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
                        }
                                             
                        int count = dictionary.count;
                        Entry[] entries = dictionary.entries;
                        try {
                            for (int i = 0; i < count; i++) {
                                if (entries[i].hashCode >= 0) objects[index++] = entries[i].key;
                            }
                        }                    
                        catch(ArrayTypeMismatchException) {
                            ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
                        }
                    }
                }
     
                bool ICollection.IsSynchronized {
                    get { return false; }
                }
     
                Object ICollection.SyncRoot { 
                    get { return ((ICollection)dictionary).SyncRoot; }
                }
     
                [Serializable]
                public struct Enumerator : IEnumerator<TKey>, System.Collections.IEnumerator
                {
                    private Dictionary<TKey, TValue> dictionary;
                    private int index;
                    private int version;
                    private TKey currentKey;
                
                    internal Enumerator(Dictionary<TKey, TValue> dictionary) {
                        this.dictionary = dictionary;
                        version = dictionary.version;
                        index = 0;
                        currentKey = default(TKey);                    
                    }
     
                    public void Dispose() {
                    }
     
                    public bool MoveNext() {
                        if (version != dictionary.version) {
                            ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
                        }
     
                        while ((uint)index < (uint)dictionary.count) {
                            if (dictionary.entries[index].hashCode >= 0) {
                                currentKey = dictionary.entries[index].key;
                                index++;
                                return true;
                            }
                            index++;
                        }
     
                        index = dictionary.count + 1;
                        currentKey = default(TKey);
                        return false;
                    }
                    
                    public TKey Current {
                        get {                        
                            return currentKey;
                        }
                    }
     
                    Object System.Collections.IEnumerator.Current {
                        get {                      
                            if( index == 0 || (index == dictionary.count + 1)) {
                                 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);                        
                            }                        
                            
                            return currentKey;
                        }
                    }
                    
                    void System.Collections.IEnumerator.Reset() {
                        if (version != dictionary.version) {
                            ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);                        
                        }
     
                        index = 0;                    
                        currentKey = default(TKey);
                    }
                }                        
            }
     
            [DebuggerTypeProxy(typeof(Mscorlib_DictionaryValueCollectionDebugView<,>))]
            [DebuggerDisplay("Count = {Count}")]
            [Serializable]
            public sealed class ValueCollection: ICollection<TValue>, ICollection, IReadOnlyCollection<TValue>
            {
                private Dictionary<TKey,TValue> dictionary;
     
                public ValueCollection(Dictionary<TKey,TValue> dictionary) {
                    if (dictionary == null) {
                        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary);
                    }
                    this.dictionary = dictionary;
                }
     
                public Enumerator GetEnumerator() {
                    return new Enumerator(dictionary);                
                }
     
                public void CopyTo(TValue[] array, int index) {
                    if (array == null) {
                        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
                    }
     
                    if (index < 0 || index > array.Length) {
                        ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
                    }
     
                    if (array.Length - index < dictionary.Count) {
                        ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
                    }
                    
                    int count = dictionary.count;
                    Entry[] entries = dictionary.entries;
                    for (int i = 0; i < count; i++) {
                        if (entries[i].hashCode >= 0) array[index++] = entries[i].value;
                    }
                }
     
                public int Count {
                    get { return dictionary.Count; }
                }
     
                bool ICollection<TValue>.IsReadOnly {
                    get { return true; }
                }
     
                void ICollection<TValue>.Add(TValue item){
                    ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ValueCollectionSet);
                }
     
                bool ICollection<TValue>.Remove(TValue item){
                    ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ValueCollectionSet);
                    return false;
                }
     
                void ICollection<TValue>.Clear(){
                    ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ValueCollectionSet);
                }
     
                bool ICollection<TValue>.Contains(TValue item){
                    return dictionary.ContainsValue(item);
                }
     
                IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator() {
                    return new Enumerator(dictionary);
                }
     
                IEnumerator IEnumerable.GetEnumerator() {
                    return new Enumerator(dictionary);                
                }
     
                void ICollection.CopyTo(Array array, int index) {
                    if (array == null) {
                        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
                    }
     
                    if (array.Rank != 1) {
                        ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
                    }
     
                    if( array.GetLowerBound(0) != 0 ) {
                        ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound);
                    }
     
                    if (index < 0 || index > array.Length) { 
                        ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
                    }
     
                    if (array.Length - index < dictionary.Count)
                        ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
                    
                    TValue[] values = array as TValue[];
                    if (values != null) {
                        CopyTo(values, index);
                    }
                    else {
                        object[] objects = array as object[];
                        if (objects == null) {
                            ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
                        }
     
                        int count = dictionary.count;
                        Entry[] entries = dictionary.entries;
                        try {
                            for (int i = 0; i < count; i++) {
                                if (entries[i].hashCode >= 0) objects[index++] = entries[i].value;
                            }
                        }
                        catch(ArrayTypeMismatchException) {
                            ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
                        }
                    }
                }
     
                bool ICollection.IsSynchronized {
                    get { return false; }
                }
     
                Object ICollection.SyncRoot { 
                    get { return ((ICollection)dictionary).SyncRoot; }
                }
     
                [Serializable]
                public struct Enumerator : IEnumerator<TValue>, System.Collections.IEnumerator
                {
                    private Dictionary<TKey, TValue> dictionary;
                    private int index;
                    private int version;
                    private TValue currentValue;
                
                    internal Enumerator(Dictionary<TKey, TValue> dictionary) {
                        this.dictionary = dictionary;
                        version = dictionary.version;
                        index = 0;
                        currentValue = default(TValue);
                    }
     
                    public void Dispose() {
                    }
     
                    public bool MoveNext() {                    
                        if (version != dictionary.version) {
                            ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
                        }
                        
                        while ((uint)index < (uint)dictionary.count) {
                            if (dictionary.entries[index].hashCode >= 0) {
                                currentValue = dictionary.entries[index].value;
                                index++;
                                return true;
                            }
                            index++;
                        }
                        index = dictionary.count + 1;
                        currentValue = default(TValue);
                        return false;
                    }
                    
                    public TValue Current {
                        get {                        
                            return currentValue;
                        }
                    }
     
                    Object System.Collections.IEnumerator.Current {
                        get {                      
                            if( index == 0 || (index == dictionary.count + 1)) {
                                 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);                        
                            }                        
                            
                            return currentValue;
                        }
                    }
                    
                    void System.Collections.IEnumerator.Reset() {
                        if (version != dictionary.version) {
                            ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
                        }
                        index = 0;                    
                        currentValue = default(TValue);
                    }
                }
            }
        }
    }
  • 相关阅读:
    Win2008 Server MySql安装包详细安装教程
    ef codefirst VS里修改数据表结构后更新到数据库
    c#扩展方法
    c#异步学习笔记
    winform SerialPort串口通信问题
    委托与事件学习笔记
    泛型的优点
    c#泛型约束 (where T:class)
    .net扩展方法
    mvc5视图view不使用默认母版页
  • 原文地址:https://www.cnblogs.com/Baron-King/p/13431630.html
Copyright © 2020-2023  润新知