//****************************************************************************************************** // ImmutableDictionary`2.cs - Gbtc // // Copyright © 2016, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/eclipse-1.0.php // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 10/24/2016 - Steven E. Chisholm // Generated original version of source code. // // //****************************************************************************************************** using System.Collections; using System.Collections.Generic; namespace GSF.Immutable { /// /// A dictionary that can be modified until is set to true. Once this occurs, /// the dictionary itself can no longer be modified. Remember, this does not cause objects contained in this class to be Immutable /// unless they implement . /// /// /// public sealed class ImmutableDictionary : ImmutableObjectBase>, IDictionary { private readonly bool m_isISupportsReadonlyKeyType; private readonly bool m_isISupportsReadonlyValueType; private Dictionary m_dictionary; /// /// Creates a new . /// public ImmutableDictionary() { m_isISupportsReadonlyKeyType = typeof(IImmutableObject).IsAssignableFrom(typeof(TKey)); m_isISupportsReadonlyValueType = typeof(IImmutableObject).IsAssignableFrom(typeof(TValue)); m_dictionary = new Dictionary(); } /// /// Creates a new . /// public ImmutableDictionary(int capacity) { m_isISupportsReadonlyKeyType = typeof(IImmutableObject).IsAssignableFrom(typeof(TKey)); m_isISupportsReadonlyValueType = typeof(IImmutableObject).IsAssignableFrom(typeof(TValue)); m_dictionary = new Dictionary(capacity); } /// /// Creates a new . /// public ImmutableDictionary(Dictionary baseDictionary) { m_dictionary = baseDictionary; m_isISupportsReadonlyKeyType = typeof(IImmutableObject).IsAssignableFrom(typeof(TKey)); m_isISupportsReadonlyValueType = typeof(IImmutableObject).IsAssignableFrom(typeof(TValue)); } IEnumerator> IEnumerable>.GetEnumerator() { return m_dictionary.GetEnumerator(); } /// Returns an enumerator that iterates through a collection. /// An object that can be used to iterate through the collection. /// 2 IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)m_dictionary).GetEnumerator(); } void ICollection>.Add(KeyValuePair item) { TestForEditable(); ((ICollection>)m_dictionary).Add(item); } /// Removes all items from the . /// The is read-only. public void Clear() { TestForEditable(); m_dictionary.Clear(); } /// Determines whether the contains a specific value. /// true if is found in the ; otherwise, false. /// The object to locate in the . public bool Contains(KeyValuePair item) { return ((ICollection>)m_dictionary).Contains(item); } /// Copies the elements of the to an , starting at a particular index. /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. /// The zero-based index in at which copying begins. public void CopyTo(KeyValuePair[] array, int arrayIndex) { ((ICollection>)m_dictionary).CopyTo(array, arrayIndex); } /// Removes the first occurrence of a specific object from the . /// true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original . /// The object to remove from the . public bool Remove(KeyValuePair item) { TestForEditable(); return ((ICollection>)m_dictionary).Remove(item); } /// Gets the number of elements contained in the . /// The number of elements contained in the . public int Count { get { return m_dictionary.Count; } } /// /// SetMembersAsReadOnly /// protected override void SetMembersAsReadOnly() { if (m_isISupportsReadonlyKeyType || m_isISupportsReadonlyValueType) { foreach (var kvp in m_dictionary) { if (m_isISupportsReadonlyKeyType) { var item = kvp.Key as IImmutableObject; if (item != null) { item.IsReadOnly = true; } } if (m_isISupportsReadonlyValueType) { var item = kvp.Value as IImmutableObject; if (item != null) { item.IsReadOnly = true; } } } } } /// /// CloneMembersAsEditable /// protected override void CloneMembersAsEditable() { if (m_isISupportsReadonlyKeyType || m_isISupportsReadonlyValueType) { var oldList = m_dictionary; m_dictionary = new Dictionary(); foreach (var kvp in oldList) { var k = kvp.Key; var v = kvp.Value; if (m_isISupportsReadonlyKeyType) { var item = k as IImmutableObject; if (item != null) { k = (TKey)item.CloneEditable(); } } if (m_isISupportsReadonlyValueType) { var item = k as IImmutableObject; if (item != null) { v = (TValue)item.CloneEditable(); } } m_dictionary.Add(k, v); } } else { m_dictionary = new Dictionary(m_dictionary); } } /// Determines whether the contains an element with the specified key. /// true if the contains an element with the key; otherwise, false. /// The key to locate in the . /// /// is null. public bool ContainsKey(TKey key) { return m_dictionary.ContainsKey(key); } /// Adds an element with the provided key and value to the . /// The object to use as the key of the element to add. /// The object to use as the value of the element to add. /// /// is null. /// An element with the same key already exists in the . /// The is read-only. public void Add(TKey key, TValue value) { TestForEditable(); m_dictionary.Add(key, value); } /// Removes the element with the specified key from the . /// true if the element is successfully removed; otherwise, false. This method also returns false if was not found in the original . /// The key of the element to remove. /// /// is null. /// The is read-only. public bool Remove(TKey key) { TestForEditable(); return m_dictionary.Remove(key); } /// Gets the value associated with the specified key. /// true if the object that implements contains an element with the specified key; otherwise, false. /// The key whose value to get. /// When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. /// /// is null. public bool TryGetValue(TKey key, out TValue value) { return m_dictionary.TryGetValue(key, out value); } /// Gets or sets the element with the specified key. /// The element with the specified key. /// The key of the element to get or set. /// /// is null. /// The property is retrieved and is not found. /// The property is set and the is read-only. public TValue this[TKey key] { get { return m_dictionary[key]; } set { TestForEditable(); m_dictionary[key] = value; } } /// Gets an containing the keys of the . /// An containing the keys of the object that implements . public ICollection Keys => m_dictionary.Keys; /// Gets an containing the values in the . /// An containing the values in the object that implements . public ICollection Values => m_dictionary.Values; } }