Question

Ma classe contient un dictionnaire < T, S > dict et je souhaite exposer un ReadOnlyCollection < T > des clés. Comment faire cela sans copier le Dictionnaire < T, S > .KeyCollection dict.Keys dans un tableau, puis exposer celui-ci en tant que ReadOnlyCollection ?

Je veux que ReadOnlyCollection soit un wrapper approprié, c'est-à-dire. pour refléter les changements dans le dictionnaire sous-jacent, et comme je le comprends bien, copier la collection dans un tableau ne le fera pas (ainsi que sembler inefficace - je ne souhaite pas réellement une nouvelle collection, mais simplement pour exposer la collection sous-jacente de clés .. .) Toutes les idées seraient très appréciées!

Éditer: J'utilise C # 2.0, donc aucune méthode d'extension telle que .ToList (facilement) n'est disponible.

Était-ce utile?

La solution

Si vous souhaitez vraiment utiliser ReadOnlyCollection < T > ;, le problème est que le constructeur de ReadOnlyCollection < T > prend un IList < T > ;, tandis que la KeyCollection du dictionnaire est uniquement un ICollection < T >.

Donc, si vous souhaitez encapsuler KeyCollection dans une ReadOnlyCollection, vous devez créer un type d'adaptateur (ou encapsuleur), implémentant IList < T > ;, encapsulant KeyCollection. Donc, cela ressemblerait à:

var dictionary = ...;
var readonly_keys = new ReadOnlyCollection<T> (new CollectionListWrapper<T> (dictionary.Keys)
);

Pas très élégant cependant, d'autant plus que KeyCollection est déjà une collection en lecture seule et que vous pouvez simplement le transmettre sous forme de ICollection < T > :)

Autres conseils

DrJokepu a déclaré qu'il pourrait être difficile d'implémenter un wrapper pour Keys Collection. Mais, dans ce cas particulier, je pense que la mise en œuvre n’est pas si difficile car, comme nous le savons, il s’agit d’un wrapper en lecture seule.

Cela nous permet d'ignorer certaines méthodes qui, dans d'autres cas, seraient difficiles à implémenter.

Voici une implémentation rapide du wrapper pour Dictionary.KeyCollection:

class MyListWrapper<T, TValue> : IList<T>
{
    private Dictionary<T, TValue>.KeyCollection keys;

    public MyListWrapper(Dictionary<T, TValue>.KeyCollection keys)
    {
        this.keys = keys;
    }

    #region IList<T> Members

    public int IndexOf(T item)
    {
        if (item == null)
            throw new ArgumentNullException();
        IEnumerator<T> e = keys.GetEnumerator();
        int i = 0;
        while (e.MoveNext())
        {
            if (e.Current.Equals(item))
                return i;
            i++;
        }
        throw new Exception("Item not found!");
    }

    public void Insert(int index, T item)
    {
        throw new NotImplementedException();
    }

    public void RemoveAt(int index)
    {
        throw new NotImplementedException();
    }

    public T this[int index]
    {
        get
        {
            IEnumerator<T> e = keys.GetEnumerator();
            if (index < 0 || index > keys.Count)
                throw new IndexOutOfRangeException();
            int i = 0;
            while (e.MoveNext() && i != index)
            {
                i++;
            }
            return e.Current;
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    #endregion

    #region ICollection<T> Members

    public void Add(T item)
    {
        throw new NotImplementedException();
    }

    public void Clear()
    {
        throw new NotImplementedException();
    }

    public bool Contains(T item)
    {
        return keys.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        keys.CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return keys.Count; }
    }

    public bool IsReadOnly
    {
        get { return true; }
    }

    public bool Remove(T item)
    {
        throw new NotImplementedException();
    }

    #endregion

    #region IEnumerable<T> Members

    public IEnumerator<T> GetEnumerator()
    {
        return keys.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return keys.GetEnumerator();
    }

    #endregion
}

Ce n'est peut-être pas la meilleure implémentation pour ces méthodes :) mais c'était simplement pour prouver que cela pouvait être fait.

En supposant que vous utilisez C # 3.0 et que vous avez:

Dictionnaire < T, S > d;

Alors

ReadOnlyCollection < T > r = new ReadOnlyCollection < T > (d.Keys.ToList ());

Vous devrez également importer l'espace de noms System.Linq.

Malheureusement, vous ne pouvez pas accéder à cette information autant que je sache sous le nom KeyCollection < T > n'expose aucun élément qui vous permettrait de le faire facilement.

Vous pouvez toutefois placer la sous-classe ReadOnlyCollection < T > de sorte que son constructeur reçoive le dictionnaire lui-même et remplace les méthodes appropriées de sorte qu'il expose les éléments du dictionnaire comme s'il s'agissait de ses propres éléments.

Pour mémoire, dans .NET 4.6, KeyCollection < T > implémente IReadOnlyCollection < T > . Si vous utilisez cette interface, vous pouvez toujours afficher les modifications apportées. Le dictionnaire contient toujours O (1) et comme l'interface est covariante, vous pouvez renvoyer IReadOnlyCollection < un type de base >

.

C'est moche, mais ça va le faire

Dictionary<int,string> dict = new Dictionary<int, string>();
...
ReadOnlyCollection<int> roc = new ReadOnlyCollection<int>((new List<int>((IEnumerable<int>)dict.Keys)));
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top