File: FrameworkFork\System.ServiceModel\System\ServiceModel\SynchronizedKeyedCollection.cs
Web Access
Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib)
// 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)
        {
            if (comparer == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("comparer"));
 
            _comparer = comparer;
            _threshold = int.MaxValue;
        }
 
        protected SynchronizedKeyedCollection(object syncRoot, IEqualityComparer<K> comparer, int dictionaryCreationThreshold)
            : base(syncRoot)
        {
            if (comparer == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("comparer"));
 
            if (dictionaryCreationThreshold < -1)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("dictionaryCreationThreshold", dictionaryCreationThreshold,
                                                    string.Format(SRServiceModel.ValueMustBeInRange, -1, int.MaxValue)));
            else if (dictionaryCreationThreshold == -1)
                _threshold = int.MaxValue;
            else
                _threshold = dictionaryCreationThreshold;
 
            _comparer = comparer;
        }
 
        public T this[K key]
        {
            get
            {
                if (key == null)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("key"));
 
                lock (this.SyncRoot)
                {
                    if (_dictionary != null)
                        return _dictionary[key];
 
                    for (int i = 0; i < this.Items.Count; i++)
                    {
                        T item = this.Items[i];
                        if (_comparer.Equals(key, this.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)
            {
                this.CreateDictionary();
                _dictionary.Add(key, item);
            }
            else
            {
                if (this.Contains(key))
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SRServiceModel.CannotAddTwoItemsWithTheSameKeyToSynchronizedKeyedCollection0));
 
                _keyCount++;
            }
        }
 
        protected void ChangeItemKey(T item, K newKey)
        {
            // check if the item exists in the collection
            if (!this.ContainsItem(item))
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SRServiceModel.ItemDoesNotExistInSynchronizedKeyedCollection0));
 
            K oldKey = this.GetKeyForItem(item);
            if (!_comparer.Equals(newKey, oldKey))
            {
                if (newKey != null)
                    this.AddKey(newKey, item);
 
                if (oldKey != null)
                    this.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("key"));
 
            lock (this.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 = this.GetKeyForItem(item);
 
            if (key != null)
                this.AddKey(key, item);
 
            base.InsertItem(index, item);
        }
 
        public bool Remove(K key)
        {
            if (key == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("key"));
 
            lock (this.SyncRoot)
            {
                if (_dictionary != null)
                {
                    if (_dictionary.ContainsKey(key))
                        return this.Remove(_dictionary[key]);
                    else
                        return false;
                }
                else
                {
                    for (int i = 0; i < Items.Count; i++)
                    {
                        if (_comparer.Equals(key, GetKeyForItem(Items[i])))
                        {
                            this.RemoveItem(i);
                            return true;
                        }
                    }
                    return false;
                }
            }
        }
 
        protected override void RemoveItem(int index)
        {
            K key = this.GetKeyForItem(this.Items[index]);
 
            if (key != null)
                this.RemoveKey(key);
 
            base.RemoveItem(index);
        }
 
        private void RemoveKey(K key)
        {
            if (!(key != null))
            {
                Fx.Assert("key shouldn't be null!");
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("key");
            }
            if (_dictionary != null)
                _dictionary.Remove(key);
            else
                _keyCount--;
        }
 
        protected override void SetItem(int index, T item)
        {
            K newKey = this.GetKeyForItem(item);
            K oldKey = this.GetKeyForItem(this.Items[index]);
 
            if (_comparer.Equals(newKey, oldKey))
            {
                if ((newKey != null) && (_dictionary != null))
                    _dictionary[newKey] = item;
            }
            else
            {
                if (newKey != null)
                    this.AddKey(newKey, item);
 
                if (oldKey != null)
                    this.RemoveKey(oldKey);
            }
            base.SetItem(index, item);
        }
    }
}