|
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.Collections.Generic
{
using System;
using System.Runtime;
using System.Runtime.InteropServices;
using System.ServiceModel;
[ComVisible(false)]
public abstract class SynchronizedKeyedCollection<K, T> : SynchronizedCollection<T>
{
const int defaultThreshold = 0;
IEqualityComparer<K> comparer;
Dictionary<K, T> dictionary;
int keyCount;
int threshold;
protected SynchronizedKeyedCollection()
{
this.comparer = EqualityComparer<K>.Default;
this.threshold = int.MaxValue;
}
protected SynchronizedKeyedCollection(object syncRoot)
: base(syncRoot)
{
this.comparer = EqualityComparer<K>.Default;
this.threshold = int.MaxValue;
}
protected SynchronizedKeyedCollection(object syncRoot, IEqualityComparer<K> comparer)
: base(syncRoot)
{
if (comparer == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("comparer"));
this.comparer = comparer;
this.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,
SR.GetString(SR.ValueMustBeInRange, -1, int.MaxValue)));
else if (dictionaryCreationThreshold == -1)
this.threshold = int.MaxValue;
else
this.threshold = dictionaryCreationThreshold;
this.comparer = comparer;
}
public T this[K key]
{
get
{
if (key == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("key"));
lock (this.SyncRoot)
{
if (this.dictionary != null)
return this.dictionary[key];
for (int i = 0; i < this.Items.Count; i++)
{
T item = this.Items[i];
if (this.comparer.Equals(key, this.GetKeyForItem(item)))
return item;
}
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new KeyNotFoundException());
}
}
}
protected IDictionary<K, T> Dictionary
{
get { return this.dictionary; }
}
void AddKey(K key, T item)
{
if (this.dictionary != null)
this.dictionary.Add(key, item);
else if (this.keyCount == this.threshold)
{
this.CreateDictionary();
this.dictionary.Add(key, item);
}
else
{
if (this.Contains(key))
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.CannotAddTwoItemsWithTheSameKeyToSynchronizedKeyedCollection0)));
this.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(SR.GetString(SR.ItemDoesNotExistInSynchronizedKeyedCollection0)));
K oldKey = this.GetKeyForItem(item);
if (!this.comparer.Equals(newKey, oldKey))
{
if (newKey != null)
this.AddKey(newKey, item);
if (oldKey != null)
this.RemoveKey(oldKey);
}
}
protected override void ClearItems()
{
base.ClearItems();
if (this.dictionary != null)
this.dictionary.Clear();
this.keyCount = 0;
}
public bool Contains(K key)
{
if (key == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("key"));
lock (this.SyncRoot)
{
if (this.dictionary != null)
return this.dictionary.ContainsKey(key);
if (key != null)
{
for (int i = 0; i < Items.Count; i++)
{
T item = Items[i];
if (this.comparer.Equals(key, GetKeyForItem(item)))
return true;
}
}
return false;
}
}
bool ContainsItem(T item)
{
K key;
if ((this.dictionary == null) || ((key = GetKeyForItem(item)) == null))
return Items.Contains(item);
T itemInDict;
if (this.dictionary.TryGetValue(key, out itemInDict))
return EqualityComparer<T>.Default.Equals(item, itemInDict);
return false;
}
void CreateDictionary()
{
this.dictionary = new Dictionary<K, T>(this.comparer);
foreach (T item in Items)
{
K key = GetKeyForItem(item);
if (key != null)
this.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 (this.dictionary != null)
{
if (this.dictionary.ContainsKey(key))
return this.Remove(this.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);
}
void RemoveKey(K key)
{
if (!(key != null))
{
Fx.Assert("key shouldn't be null!");
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("key");
}
if (this.dictionary != null)
this.dictionary.Remove(key);
else
this.keyCount--;
}
protected override void SetItem(int index, T item)
{
K newKey = this.GetKeyForItem(item);
K oldKey = this.GetKeyForItem(this.Items[index]);
if (this.comparer.Equals(newKey, oldKey))
{
if ((newKey != null) && (this.dictionary != null))
this.dictionary[newKey] = item;
}
else
{
if (newKey != null)
this.AddKey(newKey, item);
if (oldKey != null)
this.RemoveKey(oldKey);
}
base.SetItem(index, item);
}
}
}
|