| File: System\ServiceModel\SynchronizedKeyedCollection.cs | Web Access |
| Project: src\src\System.ServiceModel.Primitives\src\System.ServiceModel.Primitives.csproj (System.ServiceModel.Primitives) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Runtime; using System.Runtime.InteropServices; using System.ServiceModel; namespace System.Collections.Generic { [ComVisible(false)] public abstract class SynchronizedKeyedCollection<K, T> : SynchronizedCollection<T> { private const int defaultThreshold = 0; private IEqualityComparer<K> _comparer; private Dictionary<K, T> _dictionary; private int _keyCount; private int _threshold; protected SynchronizedKeyedCollection() { _comparer = EqualityComparer<K>.Default; _threshold = int.MaxValue; } protected SynchronizedKeyedCollection(object syncRoot) : base(syncRoot) { _comparer = EqualityComparer<K>.Default; _threshold = int.MaxValue; } protected SynchronizedKeyedCollection(object syncRoot, IEqualityComparer<K> comparer) : base(syncRoot) { _comparer = comparer ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(comparer))); _threshold = int.MaxValue; } protected SynchronizedKeyedCollection(object syncRoot, IEqualityComparer<K> comparer, int dictionaryCreationThreshold) : base(syncRoot) { if (dictionaryCreationThreshold < -1) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(dictionaryCreationThreshold), dictionaryCreationThreshold, SRP.Format(SRP.ValueMustBeInRange, -1, int.MaxValue))); } else if (dictionaryCreationThreshold == -1) { _threshold = int.MaxValue; } else { _threshold = dictionaryCreationThreshold; } _comparer = comparer ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(comparer))); } public T this[K key] { get { if (key == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(key))); } lock (SyncRoot) { if (_dictionary != null) { return _dictionary[key]; } for (int i = 0; i < Items.Count; i++) { T item = Items[i]; if (_comparer.Equals(key, GetKeyForItem(item))) { return item; } } throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new KeyNotFoundException()); } } } protected IDictionary<K, T> Dictionary { get { return _dictionary; } } private void AddKey(K key, T item) { if (_dictionary != null) { _dictionary.Add(key, item); } else if (_keyCount == _threshold) { CreateDictionary(); _dictionary.Add(key, item); } else { if (Contains(key)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SRP.CannotAddTwoItemsWithTheSameKeyToSynchronizedKeyedCollection0)); } _keyCount++; } } protected void ChangeItemKey(T item, K newKey) { // check if the item exists in the collection if (!ContainsItem(item)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SRP.ItemDoesNotExistInSynchronizedKeyedCollection0)); } K oldKey = GetKeyForItem(item); if (!_comparer.Equals(newKey, oldKey)) { if (newKey != null) { AddKey(newKey, item); } if (oldKey != null) { RemoveKey(oldKey); } } } protected override void ClearItems() { base.ClearItems(); if (_dictionary != null) { _dictionary.Clear(); } _keyCount = 0; } public bool Contains(K key) { if (key == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(key))); } lock (SyncRoot) { if (_dictionary != null) { return _dictionary.ContainsKey(key); } if (key != null) { for (int i = 0; i < Items.Count; i++) { T item = Items[i]; if (_comparer.Equals(key, GetKeyForItem(item))) { return true; } } } return false; } } private bool ContainsItem(T item) { K key; if ((_dictionary == null) || ((key = GetKeyForItem(item)) == null)) { return Items.Contains(item); } T itemInDict; if (_dictionary.TryGetValue(key, out itemInDict)) { return EqualityComparer<T>.Default.Equals(item, itemInDict); } return false; } private void CreateDictionary() { _dictionary = new Dictionary<K, T>(_comparer); foreach (T item in Items) { K key = GetKeyForItem(item); if (key != null) { _dictionary.Add(key, item); } } } protected abstract K GetKeyForItem(T item); protected override void InsertItem(int index, T item) { K key = GetKeyForItem(item); if (key != null) { AddKey(key, item); } base.InsertItem(index, item); } public bool Remove(K key) { if (key == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(key))); } lock (SyncRoot) { if (_dictionary != null) { if (_dictionary.ContainsKey(key)) { return Remove(_dictionary[key]); } else { return false; } } else { for (int i = 0; i < Items.Count; i++) { if (_comparer.Equals(key, GetKeyForItem(Items[i]))) { RemoveItem(i); return true; } } return false; } } } protected override void RemoveItem(int index) { K key = GetKeyForItem(Items[index]); if (key != null) { RemoveKey(key); } base.RemoveItem(index); } private void RemoveKey(K key) { if (!(key != null)) { Fx.Assert("key shouldn't be null!"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(key)); } if (_dictionary != null) { _dictionary.Remove(key); } else { _keyCount--; } } protected override void SetItem(int index, T item) { K newKey = GetKeyForItem(item); K oldKey = GetKeyForItem(Items[index]); if (_comparer.Equals(newKey, oldKey)) { if ((newKey != null) && (_dictionary != null)) { _dictionary[newKey] = item; } } else { if (newKey != null) { AddKey(newKey, item); } if (oldKey != null) { RemoveKey(oldKey); } } base.SetItem(index, item); } } }