From 4b4aad7217d3292650e77eec2cf4c198ea9c3b4b Mon Sep 17 00:00:00 2001 From: Jiyoung Yun Date: Wed, 23 Nov 2016 19:09:09 +0900 Subject: Imported Upstream version 1.1.0 --- .../Collections/ObjectModel/ReadOnlyDictionary.cs | 625 +++++++++++++++++++++ 1 file changed, 625 insertions(+) create mode 100644 src/mscorlib/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs (limited to 'src/mscorlib/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs') 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 : IDictionary, IDictionary, IReadOnlyDictionary + { + private readonly IDictionary m_dictionary; + [NonSerialized] + private Object m_syncRoot; + [NonSerialized] + private KeyCollection m_keys; + [NonSerialized] + private ValueCollection m_values; + + public ReadOnlyDictionary(IDictionary dictionary) { + if (dictionary == null) { + throw new ArgumentNullException("dictionary"); + } + Contract.EndContractBlock(); + m_dictionary = dictionary; + } + + protected IDictionary Dictionary { + get { return m_dictionary; } + } + + public KeyCollection Keys { + get { + Contract.Ensures(Contract.Result() != null); + if (m_keys == null) { + m_keys = new KeyCollection(m_dictionary.Keys); + } + return m_keys; + } + } + + public ValueCollection Values { + get { + Contract.Ensures(Contract.Result() != null); + if (m_values == null) { + m_values = new ValueCollection(m_dictionary.Values); + } + return m_values; + } + } + + #region IDictionary Members + + public bool ContainsKey(TKey key) { + return m_dictionary.ContainsKey(key); + } + + ICollection IDictionary.Keys { + get { + return Keys; + } + } + + public bool TryGetValue(TKey key, out TValue value) { + return m_dictionary.TryGetValue(key, out value); + } + + ICollection IDictionary.Values { + get { + return Values; + } + } + + public TValue this[TKey key] { + get { + return m_dictionary[key]; + } + } + + void IDictionary.Add(TKey key, TValue value) { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + } + + bool IDictionary.Remove(TKey key) { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + return false; + } + + TValue IDictionary.this[TKey key] { + get { + return m_dictionary[key]; + } + set { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + } + } + + #endregion + + #region ICollection> Members + + public int Count { + get { return m_dictionary.Count; } + } + + bool ICollection>.Contains(KeyValuePair item) { + return m_dictionary.Contains(item); + } + + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) { + m_dictionary.CopyTo(array, arrayIndex); + } + + bool ICollection>.IsReadOnly { + get { return true; } + } + + void ICollection>.Add(KeyValuePair item) { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + } + + void ICollection>.Clear() { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + } + + bool ICollection>.Remove(KeyValuePair item) { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + return false; + } + + #endregion + + #region IEnumerable> Members + + public IEnumerator> 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[] pairs = array as KeyValuePair[]; + 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(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(ref m_syncRoot, new Object(), null); + } + } + return m_syncRoot; + } + } + + [Serializable] + private struct DictionaryEnumerator : IDictionaryEnumerator { + private readonly IDictionary m_dictionary; + private IEnumerator> m_enumerator; + + public DictionaryEnumerator(IDictionary 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 IReadOnlyDictionary.Keys { + get { + return Keys; + } + } + + IEnumerable IReadOnlyDictionary.Values { + get { + return Values; + } + } + + #endregion IReadOnlyDictionary members + + [DebuggerTypeProxy(typeof(Mscorlib_CollectionDebugView<>))] + [DebuggerDisplay("Count = {Count}")] + [Serializable] + public sealed class KeyCollection : ICollection, ICollection, IReadOnlyCollection { + private readonly ICollection m_collection; + [NonSerialized] + private Object m_syncRoot; + + internal KeyCollection(ICollection collection) + { + if (collection == null) { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection); + } + m_collection = collection; + } + + #region ICollection Members + + void ICollection.Add(TKey item) + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + } + + void ICollection.Clear() + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + } + + bool ICollection.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.IsReadOnly { + get { return true; } + } + + bool ICollection.Remove(TKey item) + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + return false; + } + + #endregion + + #region IEnumerable Members + + public IEnumerator 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(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(ref m_syncRoot, new Object(), null); + } + } + return m_syncRoot; + } + } + + #endregion + } + + [DebuggerTypeProxy(typeof(Mscorlib_CollectionDebugView<>))] + [DebuggerDisplay("Count = {Count}")] + [Serializable] + public sealed class ValueCollection : ICollection, ICollection, IReadOnlyCollection { + private readonly ICollection m_collection; + [NonSerialized] + private Object m_syncRoot; + + internal ValueCollection(ICollection collection) + { + if (collection == null) { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection); + } + m_collection = collection; + } + + #region ICollection Members + + void ICollection.Add(TValue item) + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + } + + void ICollection.Clear() + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + } + + bool ICollection.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.IsReadOnly { + get { return true; } + } + + bool ICollection.Remove(TValue item) + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + return false; + } + + #endregion + + #region IEnumerable Members + + public IEnumerator 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(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(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(ICollection 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 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 + } +} + -- cgit v1.2.3