//******************************************************************************************************
// 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;
}
}