//****************************************************************************************************** // DictionaryList.cs - Gbtc // // Copyright © 2012, 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 MIT License (MIT), 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/MIT // // 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: // ---------------------------------------------------------------------------------------------------- // 01/07/2006 - J. Ritchie Carroll // Generated original version of source code. // 09/10/2008 - J. Ritchie Carroll // Converted to C#. // 02/19/2009 - Josh L. Patterson // Edited Code Comments. // 08/05/2009 - Josh L. Patterson // Edited Comments. // 09/14/2009 - Stephen C. Wills // Added new header and license agreement. // 12/13/2012 - Starlynn Danyelle Gilliam // Modified Header. // //****************************************************************************************************** using System.Collections; using System.Collections.Generic; namespace GSF.Collections { /// /// Represents a sorted dictionary style list that supports . /// /// /// /// Have you ever needed the quick look-up feature on a Dictionary (e.g., Hashtable), but ended /// up missing the indexed or sequential access like you have in a list? You may have wondered why /// the .NET dictionary class doesn’t implement the IList interface which allows this. The reason /// IDictionary implementations do not normally implement the IList interface is because of /// ambiguity that is caused when implementing an integer key. For example, if you created a /// dictionary style class with a key of type "Integer" that actually did implement IList(Of T), /// you would not be able to access items in the IList interface by index without "casting" the /// class as IList. This is because the Item property in both the IDictionary and IList would have /// the same parameters. Note, however, that generics in .NET 2.0 gladly allow a class to implement /// both IDictionary and IList (even specifying as Integer as the key) so long you as you are happy /// knowing that the compiler will choose if you access your items by index or key. Given that /// caveat, there are many times when you need a dictionary style collection but also desire an /// IList implementation so the class can be used in other ways without conversion. As a result of /// these needs, we’ve added a generic class to code library called a DictionaryList -- which is /// essentially just a sorted dictionary style list (i.e., SortedList) that implements the /// IList(Of T) interface (specifically as IList(Of KeyValuePair(Of TKey, TValue))). You will find /// all of your convenient expected methods related to both dictionaries and lists; that is, you can /// look-up items by key or by index. The class works perfectly for any non-Integer based key /// (e.g., String, custom class, etc.) -- note that specifying an Integer as the key for the class /// won’t cause an error, but it also will not be very useful. However, you can specify the key for /// your DictionaryList as a "Long," which allows you to use long integers for keyed look-ups and /// regular integers for indexed access--the best of both worlds! In summary, I would not change /// your programming habits to start using this for "my collection for everything," as nothing comes /// for free; however, if you have a need for a "hybrid" collection class, this fits the bill. /// /// /// Important note about using an "Integer" as the key for this class: IDictionary implementations /// do not normally implement the IList interface because of ambiguity that is caused when implementing /// an integer key. For example, if you implement this class with a key of type "Integer" you will not /// be able to access items in the queue by index without "casting" the class as IList. This is because /// the Item property in both the IDictionary and IList would have the same parameters. /// /// /// Note that prior to the addition of Generics in .NET, the class that performed a similar function /// was the "NameObjectCollectionBase" in the System.Collections.Specialized namespace which /// specifically allowed item access by either key or by index. This class is similar in function /// but instead is a generic class allowing use with any strongly typed key or value. /// /// /// Generic key type. /// Generic value type. public class DictionaryList : IList>, IDictionary { #region [ Members ] // Fields private readonly SortedList m_list; #endregion #region [ Constructors ] /// /// Creates a new . /// public DictionaryList() { m_list = new SortedList(); } #endregion #region [ Properties ] // Generic IList(Of KeyValuePair(Of TKey, TValue)) Properties /// /// Gets the number of elements contained in the . /// public int Count { get { return m_list.Count; } } /// /// Gets a value indicating whether the is read-only. /// public bool IsReadOnly { get { return false; } } /// /// Gets or sets the element at the specified index. /// /// The zero-based index of the element to get or set. /// The element at the specified index. public KeyValuePair this[int index] { get { return new KeyValuePair(m_list.Keys[index], m_list.Values[index]); } set { m_list[value.Key] = value.Value; } } // Generic IDictionary(Of TKey, TValue) Properties /// /// Gets or sets the element with the specified key. /// /// The key of the element to get or set. /// The element with the specified key. public TValue this[TKey key] { get { return m_list[key]; } set { m_list[key] = value; } } /// /// Gets an containing the keys of the . /// public ICollection Keys { get { return m_list.Keys; } } /// /// Gets an containing the values in the . /// public ICollection Values { get { return m_list.Values; } } #endregion #region [ Methods ] // Generic IList(Of KeyValuePair(Of TKey, TValue)) Methods /// /// Adds an item to the . /// /// The key value pair item to add. public void Add(KeyValuePair item) { m_list.Add(item.Key, item.Value); } /// /// Removes all items from the . /// public void Clear() { m_list.Clear(); } /// /// Determines whether the contains a specific value. /// /// The object to locate in the . /// true if item is found in the ; otherwise, false public bool Contains(KeyValuePair item) { return m_list.ContainsKey(item.Key); } /// /// 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 array must /// have zero-based indexing. /// /// The zero-based index in array at which copying begins. public void CopyTo(KeyValuePair[] array, int arrayIndex) { for (int x = 0; x < m_list.Count; x++) { array[arrayIndex + x] = new KeyValuePair(m_list.Keys[x], m_list.Values[x]); } } /// /// Removes the first occurrence of a specific object from the . /// /// The object to remove from the . /// /// true if item was successfully removed from the ; /// otherwise, false. This method also returns false if item is not found in /// the original . /// public bool Remove(KeyValuePair item) { return m_list.Remove(item.Key); } /// /// Determines the index of a specific item in the . /// /// The object to locate in the . /// The index of item if found in the list; otherwise, -1. public int IndexOf(KeyValuePair item) { return m_list.IndexOfKey(item.Key); } /// /// Removes the item at the specified index. /// /// The zero-based index of the item to remove. public void RemoveAt(int index) { m_list.RemoveAt(index); } /// /// Inserts an item to the at the specified index. /// /// The zero-based index at which item should be inserted. /// The object to insert into the . public void Insert(int index, KeyValuePair item) { // It does not matter where you try to insert the value, since it will be inserted into its sorted // location, so we just add the value. m_list.Add(item.Key, item.Value); } /// /// Returns an enumerator that iterates through the collection. /// /// A that can be used to iterate through the collection. public IEnumerator> GetEnumerator() { return m_list.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)m_list).GetEnumerator(); } // Generic IDictionary(Of TKey, TValue) Methods /// /// 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. public void Add(TKey key, TValue value) { m_list.Add(key, value); } /// /// Determines whether the contains an element with the specified key. /// /// The key to locate in the . /// true if the contains an element with the key; otherwise, false. public bool ContainsKey(TKey key) { return m_list.ContainsKey(key); } /// /// Determines whether the contains a specific value. /// /// The value to locate in the . The value can be null for reference types. /// true if the contains an element with the specified value; otherwise, false. public bool ContainsValue(TValue value) { return m_list.ContainsValue(value); } /// /// Searches for the specified key and returns the zero-based index within the entire . /// /// The key to locate in the . /// The zero-based index of key within the entire , if found; otherwise, -1. public int IndexOfKey(TKey key) { return m_list.IndexOfKey(key); } /// /// Searches for the specified value and returns the zero-based index of the first occurrence within the entire . /// /// The value to locate in the . The value can be null for reference types. /// The zero-based index of the first occurrence of value within the entire , if found; otherwise, -1. public int IndexOfValue(TValue value) { return m_list.IndexOfValue(value); } /// /// Removes the element with the specified key from the . /// /// The key of the element to remove. /// /// true if the element is successfully removed; otherwise, false. This method also returns false if key /// was not found in the original . public bool Remove(TKey key) { return m_list.Remove(key); } /// /// Gets the value associated with the specified key. /// /// 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 value /// parameter. This parameter is passed uninitialized. /// /// true if the contains an element with the specified key; otherwise, false. public bool TryGetValue(TKey key, out TValue value) { return m_list.TryGetValue(key, out value); } #endregion } }