using System.Collections; using System.Collections.Generic; using System.Linq; namespace Developpez.Dotnet.Collections { /// /// Dictionnaire qui maintient ses éléments dans l'ordre où ils ont été ajoutés /// /// Type de la clé /// Type de la valeur public class OrderedDictionary : IDictionary { private readonly object _syncLock = new object(); private readonly Dictionary>> _nodes; private readonly LinkedList> _entries; /// /// Initialise une nouvelle instance vide de OrderedDictionary, qui utilise /// le comparateur spécifié pour tester l'égalité des clés. /// /// Comparateur utilisé pour tester l'égalité des clés public OrderedDictionary(IEqualityComparer comparer) { _nodes = new Dictionary>>(comparer); _entries = new LinkedList>(); } /// /// Initialise une nouvelle instance vide de OrderedDictionary /// public OrderedDictionary() : this (default(IEqualityComparer)) { } /// /// Initialise une nouvelle instance de OrderedDictionary qui contient les /// éléments du dictionnaire spécifié et utilise le comparateur spécifié /// pour tester l'égalité des clés. /// /// Dictionnaire à partir duquel copier les éléments /// Comparateur utilisé pour tester l'égalité des clés public OrderedDictionary(IDictionary dictionary, IEqualityComparer comparer) : this(comparer) { foreach (var kvp in dictionary) { this.Add(kvp.Key, kvp.Value); } } /// /// Initialise une nouvelle instance de OrderedDictionary qui contient les /// éléments du dictionnaire spécifié. /// /// Dictionnaire à partir duquel copier les éléments public OrderedDictionary(IDictionary dictionary) : this(dictionary, null) { } #region Implementation of IEnumerable /// /// Retourne un énumérateur qui parcourt le dictionnaire /// /// Un énumerateur pour parcourir le dictionnaire public IEnumerator> GetEnumerator() { return _entries.GetEnumerator(); } /// /// Retourne un énumérateur qui parcourt le dictionnaire /// /// Un énumerateur pour parcourir le dictionnaire IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion #region Implementation of ICollection> /// /// Ajoute la paire clé/valeur spécifiée au dictionnaire /// /// Paire clé/valeur à ajouter public void Add(KeyValuePair item) { Add(item.Key, item.Value); } /// /// Supprime toutes les clés et les valeurs du dictionnaire. /// public void Clear() { lock (_syncLock) { _entries.Clear(); _nodes.Clear(); } } /// /// Détermine si le dictionnaire contient la paire clé/valeur spécifiée. /// /// Paire clé/valeur recherchée /// true si le dictionnaire contient la paire clé/valeur, false sinon public bool Contains(KeyValuePair item) { lock (_syncLock) { TValue value; if (TryGetValue(item.Key, out value)) return EqualityComparer.Default.Equals(item.Value, value); return false; } } /// /// Copie les éléments du dictionnaire dans un tableau, à partir de la position spécifiée /// /// Tableau de destination /// Index du tableau où commencer la copie public void CopyTo(KeyValuePair[] array, int arrayIndex) { lock (_syncLock) { this.CopyTo(array, arrayIndex); } } /// /// Supprime du dictionnaire la paire clé/valeur spécifiée. /// /// Paire clé/valeur /// true si la recherche et la suppression de l'élément réussissent ; sinon, false. public bool Remove(KeyValuePair item) { lock (_syncLock) { LinkedListNode> node; if (_nodes.TryGetValue(item.Key, out node)) { if (EqualityComparer.Default.Equals(item.Value, node.Value.Value)) return Remove(item.Key); } return false; } } /// /// Obtient le nombre de paires clé/valeur contenues dans le dictionnaire. /// public int Count { get { return _nodes.Count; } } /// /// Obtient une valeur indiquant si le dictionnaire est en lecture seule. /// public bool IsReadOnly { get { return false; } } #endregion #region Implementation of IDictionary /// /// Détermine si le dictionnaire contient la clé spécifiée. /// /// Clé à rechercher /// true si le dictionnaire contient un élément correspondant à la clé spécifiée ; sinon, false. /// Cette méthode est proche d'une opération en O(1). public bool ContainsKey(TKey key) { return _nodes.ContainsKey(key); } /// /// Ajoute la clé et la valeur spécifiées au dictionnaire. /// /// Clé de l'élément à ajouter. /// Valeur de l'élément à ajouter. La valeur peut être null pour les types référence. /// Cette méthode est proche d'une opération en O(1) si la capacité interne est suffisante. /// Si la capacité doit être augmentée, cette méthode devient une opération en O(n). public void Add(TKey key, TValue value) { lock (_syncLock) { var entry = new KeyValuePair(key, value); var node = new LinkedListNode>(entry); _nodes.Add(key, node); _entries.AddLast(node); } } /// /// Supprime du dictionnaire la valeur ayant la clé spécifiée. /// /// Clé de l'élément à supprimer. /// true si la recherche et la suppression de l'élément réussissent ; sinon, false. /// Cette méthode est proche d'une opération en O(1). public bool Remove(TKey key) { lock (_syncLock) { LinkedListNode> node; if (_nodes.TryGetValue(key, out node)) { _nodes.Remove(key); _entries.Remove(node); return true; } return false; } } /// /// Obtient la valeur associée à la clé spécifiée. /// /// Clé de la valeur à obtenir. /// Paramètre de sortie auquel est affecté la valeur trouvée /// true si le dictionnaire contient un élément correspondant à la clé spécifiée ; sinon, false. /// Cette méthode est proche d'une opération en O(1). public bool TryGetValue(TKey key, out TValue value) { LinkedListNode> node; if (_nodes.TryGetValue(key, out node)) { value = node.Value.Value; return true; } value = default(TValue); return false; } /// /// Obtient ou définit la valeur associée à la clé spécifiée. /// /// Clé de l'élément à obtenir ou à définir /// Valeur associée à la clé spécifiée. Si la clé spécifiée est introuvable, une opération Get retourne KeyNotFoundException et une opération Set crée un nouvel élément avec la clé spécifiée. /// Obtenir la valeur de cette propriété est proche d'une opération en O(1). Définir la valeur /// de cette propriété est proche d'une opération en O(1) si la capacité interne est suffisante /// ou que la clé est déjà présente dans le dictionnaire. Si la clé n'est pas déjà présente et que /// la capacité doit être augmentée, définir la valeur devient une opération en O(n). public TValue this[TKey key] { get { lock (_syncLock) { TValue value; if (TryGetValue(key, out value)) return value; throw new KeyNotFoundException(); } } set { lock (_syncLock) { LinkedListNode> node; if (_nodes.TryGetValue(key, out node)) { node.Value = new KeyValuePair(key, value); } else { Add(key, value); } } } } /// /// Obtient une collection contenant les clés du dictionnaire. /// /// Les clés sont renvoyées dans l'ordre où elles ont été ajoutées. public ICollection Keys { get { lock (_syncLock) { var keys = _entries.Select(e => e.Key); return keys.ToList().AsReadOnly(); } } } /// /// Obtient une collection contenant les valeurs du dictionnaire. /// /// Les valeurs sont renvoyées dans l'ordre où elles ont été ajoutées. public ICollection Values { get { lock (_syncLock) { var values = _entries.Select(e => e.Value); return values.ToList().AsReadOnly(); } } } #endregion } }