using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; namespace Caliburn.MemoryManagement { /// /// Represents a dictionary mapping keys to values. /// /// /// /// Provides the plumbing for the portions of IDictionary which can reasonably be implemented without any /// dependency on the underlying representation of the dictionary. /// [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(PREFIX + "DictionaryDebugView`2" + SUFFIX)] public abstract class BaseDictionary : IDictionary { private const string PREFIX = "System.Collections.Generic.Mscorlib_"; private const string SUFFIX = ",mscorlib,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089"; private KeyCollection keys; private ValueCollection values; #region IDictionary Members public abstract int Count { get; } public abstract void Clear(); public abstract void Add(TKey key, TValue value); public abstract bool ContainsKey(TKey key); public abstract bool Remove(TKey key); public abstract bool TryGetValue(TKey key, out TValue value); public abstract IEnumerator> GetEnumerator(); public bool IsReadOnly { get { return false; } } public ICollection Keys { get { if(keys == null) keys = new KeyCollection(this); return keys; } } public ICollection Values { get { if(values == null) values = new ValueCollection(this); return values; } } public TValue this[TKey key] { get { TValue value; if(!TryGetValue(key, out value)) throw new KeyNotFoundException(); return value; } set { SetValue(key, value); } } public void Add(KeyValuePair item) { Add(item.Key, item.Value); } public bool Contains(KeyValuePair item) { TValue value; if(!TryGetValue(item.Key, out value)) return false; return EqualityComparer.Default.Equals(value, item.Value); } public void CopyTo(KeyValuePair[] array, int arrayIndex) { Copy(this, array, arrayIndex); } public bool Remove(KeyValuePair item) { if(!Contains(item)) return false; return Remove(item.Key); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion protected abstract void SetValue(TKey key, TValue value); private static void Copy(ICollection source, T[] array, int arrayIndex) { if(array == null) throw new ArgumentNullException("array"); if(arrayIndex < 0 || arrayIndex > array.Length) throw new ArgumentOutOfRangeException("arrayIndex"); if((array.Length - arrayIndex) < source.Count) throw new ArgumentException("Destination array is not large enough. Check array.Length and arrayIndex."); foreach(T item in source) array[arrayIndex++] = item; } #region Nested type: Collection private abstract class Collection : ICollection { protected readonly IDictionary dictionary; protected Collection(IDictionary dictionary) { this.dictionary = dictionary; } #region ICollection Members public int Count { get { return dictionary.Count; } } public bool IsReadOnly { get { return true; } } public void CopyTo(T[] array, int arrayIndex) { Copy(this, array, arrayIndex); } public virtual bool Contains(T item) { foreach(T element in this) if(EqualityComparer.Default.Equals(element, item)) return true; return false; } public IEnumerator GetEnumerator() { foreach(KeyValuePair pair in dictionary) yield return GetItem(pair); } public bool Remove(T item) { throw new NotSupportedException("Collection is read-only."); } public void Add(T item) { throw new NotSupportedException("Collection is read-only."); } public void Clear() { throw new NotSupportedException("Collection is read-only."); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion protected abstract T GetItem(KeyValuePair pair); } #endregion #region Nested type: KeyCollection [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(PREFIX + "DictionaryKeyCollectionDebugView`2" + SUFFIX)] private class KeyCollection : Collection { public KeyCollection(IDictionary dictionary) : base(dictionary) {} protected override TKey GetItem(KeyValuePair pair) { return pair.Key; } public override bool Contains(TKey item) { return dictionary.ContainsKey(item); } } #endregion #region Nested type: ValueCollection [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(PREFIX + "DictionaryValueCollectionDebugView`2" + SUFFIX)] private class ValueCollection : Collection { public ValueCollection(IDictionary dictionary) : base(dictionary) {} protected override TValue GetItem(KeyValuePair pair) { return pair.Value; } } #endregion } }