注意: 粗糙版手账,未经测试,请谨慎使用
Check.NotNull: 别处定义的帮助类方法,与主要功能无关
using System;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Linq;namespace System.Collections.Generic
{public class OrderedDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue>{private readonly List<TKey> _keys;private readonly List<TValue> _values;private readonly IEqualityComparer<TKey> _comparer;private bool _isReadOnly;private readonly object _lock = new object();public OrderedDictionary(){_keys = new List<TKey>();_values = new List<TValue>();_comparer = EqualityComparer<TKey>.Default;}public OrderedDictionary(IEqualityComparer<TKey> comparer){_comparer = comparer ?? EqualityComparer<TKey>.Default;}public OrderedDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer){Check.NotNull(collection, nameof(collection));_keys = collection.Select(x => x.Key).ToList();_values = collection.Select(x => x.Value).ToList();_comparer = comparer ?? EqualityComparer<TKey>.Default;}public OrderedDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer){Check.NotNull(dictionary, nameof(dict));_keys = dictionary.Keys.ToList();_values = dictionary.Values.ToList();_comparer = comparer ?? EqualityComparer<TKey>.Default;}public ICollection<TKey> Keys => _keys;public ICollection<TValue> Values => _values;public IEqualityComparer<TKey> Comparer => _comparer;public int Count => Keys.Count;public bool IsReadOnly => _isReadOnly;IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => Keys;IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => Values;public TValue this[TKey key]{get{for (int i = 0; i < Count; i++){if (_comparer.Equals(key, _keys[i])){return _values[i];}}throw new KeyNotFoundException($"The given key `{key}` was not present in the dictionary.");}set{if (IsReadOnly){throw new InvalidOperationException("The dictionary is read-only.");}lock (_lock){bool found = false;for (int i = 0; i < Count; i++){if (_comparer.Equals(key, _keys[i])){found = true;_values[i] = value;}}if (!found){Add(key, value);}}}}private void CheckReadOnly(){if (IsReadOnly){throw new InvalidOperationException("The dictionary is read-only.");}}public void Add(TKey key, TValue value){CheckReadOnly();lock (_lock){if (ContainsKey(key)){throw new ArgumentException($"An item with the same key has already been added. Key: {key}");}_keys.Add(key);_values.Add(value);}}public bool ContainsKey(TKey key){return Keys.Contains(key, _comparer);}public bool Remove(TKey key){CheckReadOnly();lock (_lock){for (int i = 0; i < Count; i++){if (_comparer.Equals(key, _keys[i])){_keys.RemoveAt(i);_values.RemoveAt(i);return true;}}return false;}}public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value){for (int i = 0; i < Count; i++){if (_comparer.Equals(key, _keys[i])){value = _values[i];return true;}}value = default;return false;}public void Add(KeyValuePair<TKey, TValue> item){Check.NotNull(item, nameof(item));Add(item.Key, item.Value);}public void Clear(){CheckReadOnly();lock (_lock){_keys.Clear();_values.Clear();}}public bool Contains(KeyValuePair<TKey, TValue> item){Check.NotNull(item, nameof(item));return ContainsKey(item.Key);}public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex){Check.NotNull(array, nameof(array));if (arrayIndex > array.Length){throw new ArgumentOutOfRangeException(nameof(arrayIndex));}if (array.Length - arrayIndex < Count){throw new ArgumentException("The array is too small.");}int count = Count;for (int i = 0; i < count; i++){array[arrayIndex++] = new KeyValuePair<TKey, TValue>(_keys[i], _values[i]);}}public bool Remove(KeyValuePair<TKey, TValue> item){Check.NotNull(item, nameof(item));return Remove(item.Key);}public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator(){for (int i = 0; i < Count; i++)yield return new KeyValuePair<TKey, TValue>(_keys[i], _values[i]);}IEnumerator IEnumerable.GetEnumerator(){return GetEnumerator();}}
}