|
//------------------------------------------------------------------------------
// <copyright file="OrderedDictionary.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Util {
using System;
using System.Collections;
using System.Collections.Generic;
// This is different from the BCL's SortedDictionary in that SortedDictionary sorts by the keys'
// values (e.g., alphabetical order), but OrderedDictionary sorts by the order in which the keys
// were inserted into the dictionary.
internal class OrderedDictionary<TKey, TValue> : IDictionary<TKey, TValue> {
private Dictionary<TKey, TValue> _dictionary;
private List<TKey> _keys;
private List<TValue> _values;
// Cannot easily support ctor that takes IEqualityComparer, since List doesn't have an easy
// way to use the IEqualityComparer.
public OrderedDictionary()
: this(0) {
}
public OrderedDictionary(int capacity) {
_dictionary = new Dictionary<TKey, TValue>(capacity);
_keys = new List<TKey>(capacity);
_values = new List<TValue>(capacity);
}
public int Count {
get {
return _dictionary.Count;
}
}
public ICollection<TKey> Keys {
get {
return _keys.AsReadOnly();
}
}
public TValue this[TKey key] {
get {
return _dictionary[key];
}
set {
// If key has already been added, we must first remove it from the lists so it is not
// in the lists multiple times.
RemoveFromLists(key);
_dictionary[key] = value;
_keys.Add(key);
_values.Add(value);
}
}
public ICollection<TValue> Values {
get {
return _values.AsReadOnly();
}
}
public void Add(TKey key, TValue value) {
// Dictionary.Add() will throw if it already contains key
_dictionary.Add(key, value);
_keys.Add(key);
_values.Add(value);
}
public void Clear() {
_dictionary.Clear();
_keys.Clear();
_values.Clear();
}
public bool ContainsKey(TKey key) {
return _dictionary.ContainsKey(key);
}
public bool ContainsValue(TValue value) {
return _dictionary.ContainsValue(value);
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
int i = 0;
// Must use foreach instead of a for loop, since we want the underlying List enumerator to
// throw an exception if the list is modified during enumeration.
foreach (TKey key in _keys) {
yield return new KeyValuePair<TKey, TValue>(key, _values[i]);
i++;
}
}
private void RemoveFromLists(TKey key) {
int index = _keys.IndexOf(key);
if (index != -1) {
_keys.RemoveAt(index);
_values.RemoveAt(index);
}
}
public bool Remove(TKey key) {
RemoveFromLists(key);
return _dictionary.Remove(key);
}
public bool TryGetValue(TKey key, out TValue value) {
return _dictionary.TryGetValue(key, out value);
}
#region ICollection<KeyValuePair<TKey,TValue>> Members
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly {
get {
return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).IsReadOnly;
}
}
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) {
Add(item.Key, item.Value);
}
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) {
return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Contains(item);
}
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).CopyTo(array, arrayIndex);
}
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) {
bool removed = ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Remove(item);
// Only remove from lists if it was removed from the dictionary, since the dictionary may contain
// the key but not the value.
if (removed) {
RemoveFromLists(item.Key);
}
return removed;
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
#endregion
}
}
|