summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs')
-rw-r--r--src/mscorlib/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs625
1 files changed, 625 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs b/src/mscorlib/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs
new file mode 100644
index 0000000000..11833c2c1b
--- /dev/null
+++ b/src/mscorlib/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs
@@ -0,0 +1,625 @@
+// 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.
+
+/*============================================================
+**
+**
+**
+**
+** Purpose: Read-only wrapper for another generic dictionary.
+**
+===========================================================*/
+
+namespace System.Collections.ObjectModel
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Diagnostics.Contracts;
+
+ [Serializable]
+ [DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<,>))]
+ [DebuggerDisplay("Count = {Count}")]
+ public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue>
+ {
+ private readonly IDictionary<TKey, TValue> m_dictionary;
+ [NonSerialized]
+ private Object m_syncRoot;
+ [NonSerialized]
+ private KeyCollection m_keys;
+ [NonSerialized]
+ private ValueCollection m_values;
+
+ public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary) {
+ if (dictionary == null) {
+ throw new ArgumentNullException("dictionary");
+ }
+ Contract.EndContractBlock();
+ m_dictionary = dictionary;
+ }
+
+ protected IDictionary<TKey, TValue> Dictionary {
+ get { return m_dictionary; }
+ }
+
+ public KeyCollection Keys {
+ get {
+ Contract.Ensures(Contract.Result<KeyCollection>() != null);
+ if (m_keys == null) {
+ m_keys = new KeyCollection(m_dictionary.Keys);
+ }
+ return m_keys;
+ }
+ }
+
+ public ValueCollection Values {
+ get {
+ Contract.Ensures(Contract.Result<ValueCollection>() != null);
+ if (m_values == null) {
+ m_values = new ValueCollection(m_dictionary.Values);
+ }
+ return m_values;
+ }
+ }
+
+ #region IDictionary<TKey, TValue> Members
+
+ public bool ContainsKey(TKey key) {
+ return m_dictionary.ContainsKey(key);
+ }
+
+ ICollection<TKey> IDictionary<TKey, TValue>.Keys {
+ get {
+ return Keys;
+ }
+ }
+
+ public bool TryGetValue(TKey key, out TValue value) {
+ return m_dictionary.TryGetValue(key, out value);
+ }
+
+ ICollection<TValue> IDictionary<TKey, TValue>.Values {
+ get {
+ return Values;
+ }
+ }
+
+ public TValue this[TKey key] {
+ get {
+ return m_dictionary[key];
+ }
+ }
+
+ void IDictionary<TKey, TValue>.Add(TKey key, TValue value) {
+ ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
+ }
+
+ bool IDictionary<TKey, TValue>.Remove(TKey key) {
+ ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
+ return false;
+ }
+
+ TValue IDictionary<TKey, TValue>.this[TKey key] {
+ get {
+ return m_dictionary[key];
+ }
+ set {
+ ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
+ }
+ }
+
+ #endregion
+
+ #region ICollection<KeyValuePair<TKey, TValue>> Members
+
+ public int Count {
+ get { return m_dictionary.Count; }
+ }
+
+ bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) {
+ return m_dictionary.Contains(item);
+ }
+
+ void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
+ m_dictionary.CopyTo(array, arrayIndex);
+ }
+
+ bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly {
+ get { return true; }
+ }
+
+ void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) {
+ ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
+ }
+
+ void ICollection<KeyValuePair<TKey, TValue>>.Clear() {
+ ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
+ }
+
+ bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) {
+ ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
+ return false;
+ }
+
+ #endregion
+
+ #region IEnumerable<KeyValuePair<TKey, TValue>> Members
+
+ public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
+ return m_dictionary.GetEnumerator();
+ }
+
+ #endregion
+
+ #region IEnumerable Members
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
+ return ((IEnumerable)m_dictionary).GetEnumerator();
+ }
+
+ #endregion
+
+ #region IDictionary Members
+
+ private static bool IsCompatibleKey(object key) {
+ if (key == null) {
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
+ }
+ return key is TKey;
+ }
+
+ void IDictionary.Add(object key, object value) {
+ ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
+ }
+
+ void IDictionary.Clear() {
+ ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
+ }
+
+ bool IDictionary.Contains(object key) {
+ return IsCompatibleKey(key) && ContainsKey((TKey)key);
+ }
+
+ IDictionaryEnumerator IDictionary.GetEnumerator() {
+ IDictionary d = m_dictionary as IDictionary;
+ if (d != null) {
+ return d.GetEnumerator();
+ }
+ return new DictionaryEnumerator(m_dictionary);
+ }
+
+ bool IDictionary.IsFixedSize {
+ get { return true; }
+ }
+
+ bool IDictionary.IsReadOnly {
+ get { return true; }
+ }
+
+ ICollection IDictionary.Keys {
+ get {
+ return Keys;
+ }
+ }
+
+ void IDictionary.Remove(object key) {
+ ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
+ }
+
+ ICollection IDictionary.Values {
+ get {
+ return Values;
+ }
+ }
+
+ object IDictionary.this[object key] {
+ get {
+ if (IsCompatibleKey(key)) {
+ return this[(TKey)key];
+ }
+ return null;
+ }
+ set {
+ ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
+ }
+ }
+
+ 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) {
+ m_dictionary.CopyTo(pairs, index);
+ }
+ else {
+ DictionaryEntry[] dictEntryArray = array as DictionaryEntry[];
+ if (dictEntryArray != null) {
+ foreach (var item in m_dictionary) {
+ dictEntryArray[index++] = new DictionaryEntry(item.Key, item.Value);
+ }
+ }
+ else {
+ object[] objects = array as object[];
+ if (objects == null) {
+ ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
+ }
+
+ try {
+ foreach (var item in m_dictionary) {
+ objects[index++] = new KeyValuePair<TKey, TValue>(item.Key, item.Value);
+ }
+ }
+ catch (ArrayTypeMismatchException) {
+ ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
+ }
+ }
+ }
+ }
+
+ bool ICollection.IsSynchronized {
+ get { return false; }
+ }
+
+ object ICollection.SyncRoot {
+ get {
+ if (m_syncRoot == null) {
+ ICollection c = m_dictionary as ICollection;
+ if (c != null) {
+ m_syncRoot = c.SyncRoot;
+ }
+ else {
+ System.Threading.Interlocked.CompareExchange<Object>(ref m_syncRoot, new Object(), null);
+ }
+ }
+ return m_syncRoot;
+ }
+ }
+
+ [Serializable]
+ private struct DictionaryEnumerator : IDictionaryEnumerator {
+ private readonly IDictionary<TKey, TValue> m_dictionary;
+ private IEnumerator<KeyValuePair<TKey, TValue>> m_enumerator;
+
+ public DictionaryEnumerator(IDictionary<TKey, TValue> dictionary) {
+ m_dictionary = dictionary;
+ m_enumerator = m_dictionary.GetEnumerator();
+ }
+
+ public DictionaryEntry Entry {
+ get { return new DictionaryEntry(m_enumerator.Current.Key, m_enumerator.Current.Value); }
+ }
+
+ public object Key {
+ get { return m_enumerator.Current.Key; }
+ }
+
+ public object Value {
+ get { return m_enumerator.Current.Value; }
+ }
+
+ public object Current {
+ get { return Entry; }
+ }
+
+ public bool MoveNext() {
+ return m_enumerator.MoveNext();
+ }
+
+ public void Reset() {
+ m_enumerator.Reset();
+ }
+ }
+
+ #endregion
+
+ #region IReadOnlyDictionary members
+
+ IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys {
+ get {
+ return Keys;
+ }
+ }
+
+ IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values {
+ get {
+ return Values;
+ }
+ }
+
+ #endregion IReadOnlyDictionary members
+
+ [DebuggerTypeProxy(typeof(Mscorlib_CollectionDebugView<>))]
+ [DebuggerDisplay("Count = {Count}")]
+ [Serializable]
+ public sealed class KeyCollection : ICollection<TKey>, ICollection, IReadOnlyCollection<TKey> {
+ private readonly ICollection<TKey> m_collection;
+ [NonSerialized]
+ private Object m_syncRoot;
+
+ internal KeyCollection(ICollection<TKey> collection)
+ {
+ if (collection == null) {
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
+ }
+ m_collection = collection;
+ }
+
+ #region ICollection<T> Members
+
+ void ICollection<TKey>.Add(TKey item)
+ {
+ ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
+ }
+
+ void ICollection<TKey>.Clear()
+ {
+ ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
+ }
+
+ bool ICollection<TKey>.Contains(TKey item)
+ {
+ return m_collection.Contains(item);
+ }
+
+ public void CopyTo(TKey[] array, int arrayIndex)
+ {
+ m_collection.CopyTo(array, arrayIndex);
+ }
+
+ public int Count {
+ get { return m_collection.Count; }
+ }
+
+ bool ICollection<TKey>.IsReadOnly {
+ get { return true; }
+ }
+
+ bool ICollection<TKey>.Remove(TKey item)
+ {
+ ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
+ return false;
+ }
+
+ #endregion
+
+ #region IEnumerable<T> Members
+
+ public IEnumerator<TKey> GetEnumerator()
+ {
+ return m_collection.GetEnumerator();
+ }
+
+ #endregion
+
+ #region IEnumerable Members
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
+ return ((IEnumerable)m_collection).GetEnumerator();
+ }
+
+ #endregion
+
+ #region ICollection Members
+
+ void ICollection.CopyTo(Array array, int index) {
+ ReadOnlyDictionaryHelpers.CopyToNonGenericICollectionHelper<TKey>(m_collection, array, index);
+ }
+
+ bool ICollection.IsSynchronized {
+ get { return false; }
+ }
+
+ object ICollection.SyncRoot {
+ get {
+ if (m_syncRoot == null) {
+ ICollection c = m_collection as ICollection;
+ if (c != null) {
+ m_syncRoot = c.SyncRoot;
+ }
+ else {
+ System.Threading.Interlocked.CompareExchange<Object>(ref m_syncRoot, new Object(), null);
+ }
+ }
+ return m_syncRoot;
+ }
+ }
+
+ #endregion
+ }
+
+ [DebuggerTypeProxy(typeof(Mscorlib_CollectionDebugView<>))]
+ [DebuggerDisplay("Count = {Count}")]
+ [Serializable]
+ public sealed class ValueCollection : ICollection<TValue>, ICollection, IReadOnlyCollection<TValue> {
+ private readonly ICollection<TValue> m_collection;
+ [NonSerialized]
+ private Object m_syncRoot;
+
+ internal ValueCollection(ICollection<TValue> collection)
+ {
+ if (collection == null) {
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
+ }
+ m_collection = collection;
+ }
+
+ #region ICollection<T> Members
+
+ void ICollection<TValue>.Add(TValue item)
+ {
+ ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
+ }
+
+ void ICollection<TValue>.Clear()
+ {
+ ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
+ }
+
+ bool ICollection<TValue>.Contains(TValue item)
+ {
+ return m_collection.Contains(item);
+ }
+
+ public void CopyTo(TValue[] array, int arrayIndex)
+ {
+ m_collection.CopyTo(array, arrayIndex);
+ }
+
+ public int Count {
+ get { return m_collection.Count; }
+ }
+
+ bool ICollection<TValue>.IsReadOnly {
+ get { return true; }
+ }
+
+ bool ICollection<TValue>.Remove(TValue item)
+ {
+ ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
+ return false;
+ }
+
+ #endregion
+
+ #region IEnumerable<T> Members
+
+ public IEnumerator<TValue> GetEnumerator()
+ {
+ return m_collection.GetEnumerator();
+ }
+
+ #endregion
+
+ #region IEnumerable Members
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
+ return ((IEnumerable)m_collection).GetEnumerator();
+ }
+
+ #endregion
+
+ #region ICollection Members
+
+ void ICollection.CopyTo(Array array, int index) {
+ ReadOnlyDictionaryHelpers.CopyToNonGenericICollectionHelper<TValue>(m_collection, array, index);
+ }
+
+ bool ICollection.IsSynchronized {
+ get { return false; }
+ }
+
+ object ICollection.SyncRoot {
+ get {
+ if (m_syncRoot == null) {
+ ICollection c = m_collection as ICollection;
+ if (c != null) {
+ m_syncRoot = c.SyncRoot;
+ }
+ else {
+ System.Threading.Interlocked.CompareExchange<Object>(ref m_syncRoot, new Object(), null);
+ }
+ }
+ return m_syncRoot;
+ }
+ }
+
+ #endregion ICollection Members
+ }
+ }
+
+ // To share code when possible, use a non-generic class to get rid of irrelevant type parameters.
+ internal static class ReadOnlyDictionaryHelpers
+ {
+ #region Helper method for our KeyCollection and ValueCollection
+
+ // Abstracted away to avoid redundant implementations.
+ internal static void CopyToNonGenericICollectionHelper<T>(ICollection<T> collection, 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) {
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.arrayIndex, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
+ }
+
+ if (array.Length - index < collection.Count) {
+ ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
+ }
+
+ // Easy out if the ICollection<T> implements the non-generic ICollection
+ ICollection nonGenericCollection = collection as ICollection;
+ if (nonGenericCollection != null) {
+ nonGenericCollection.CopyTo(array, index);
+ return;
+ }
+
+ T[] items = array as T[];
+ if (items != null) {
+ collection.CopyTo(items, index);
+ }
+ else {
+ //
+ // Catch the obvious case assignment will fail.
+ // We can found all possible problems by doing the check though.
+ // For example, if the element type of the Array is derived from T,
+ // we can't figure out if we can successfully copy the element beforehand.
+ //
+ Type targetType = array.GetType().GetElementType();
+ Type sourceType = typeof(T);
+ if (!(targetType.IsAssignableFrom(sourceType) || sourceType.IsAssignableFrom(targetType))) {
+ ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
+ }
+
+ //
+ // We can't cast array of value type to object[], so we don't support
+ // widening of primitive types here.
+ //
+ object[] objects = array as object[];
+ if (objects == null) {
+ ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
+ }
+
+ try {
+ foreach (var item in collection) {
+ objects[index++] = item;
+ }
+ }
+ catch (ArrayTypeMismatchException) {
+ ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
+ }
+ }
+ }
+
+ #endregion Helper method for our KeyCollection and ValueCollection
+ }
+}
+