Domanda

La mia classe contiene un dizionario < T, S > dict e desidero esporre un ReadOnlyCollection < T > delle chiavi. Come posso farlo senza copiare il Dizionario < T, S > .KeyCollection dict.Keys su un array e quindi esponendolo come ReadOnlyCollection ?

Voglio che ReadOnlyCollection sia un wrapper appropriato, ad es. riflettere i cambiamenti nel Dizionario sottostante e, a quanto ho capito, copiare la raccolta in un array non lo farà (oltre a sembrare inefficiente - In realtà non voglio una nuova raccolta, ma solo per esporre la raccolta di chiavi sottostante. .). Qualsiasi idea sarebbe molto apprezzata!

Modifica: sto usando C # 2.0, quindi non ho metodi di estensione come .ToList (facilmente) disponibili.

È stato utile?

Soluzione

Se vuoi davvero utilizzare ReadOnlyCollection < T > ;, il problema è che il costruttore di ReadOnlyCollection < T > prende un IList < T > ;, mentre KeyCollection del Dizionario è solo un ICollection < T > ;.

Quindi, se vuoi avvolgere KeyCollection in ReadOnlyCollection, dovrai creare un tipo di adattatore (o wrapper), implementando IList < T > ;, avvolgendo KeyCollection. Quindi sembrerebbe:

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

Non molto elegante, soprattutto perché KeyCollection è già una raccolta di sola lettura e che potresti semplicemente passarlo come ICollection < T > :)

Altri suggerimenti

DrJokepu ha affermato che potrebbe essere difficile implementare un wrapper per Keys Collection. Ma, in questo caso particolare, penso che l'implementazione non sia così difficile perché, come sappiamo, questo è un wrapper di sola lettura.

Questo ci consente di ignorare alcuni metodi che, in altri casi, sarebbero difficili da implementare.

Ecco una rapida implementazione del wrapper per 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
}

Questa potrebbe non essere la migliore implementazione per questi metodi :) ma era solo per dimostrare che ciò poteva essere fatto.

Supponendo che tu stia utilizzando C # 3.0 e hai:

dizionario < T, S > d;

Poi

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

Dovrai anche importare lo spazio dei nomi System.Linq.

Sfortunatamente non puoi farlo direttamente per quanto ne so KeyCollection < T > non espone nulla che ti consenta di farlo facilmente.

Tuttavia, puoi sottoclassare ReadOnlyCollection < T > in modo che il suo costruttore riceva il dizionario stesso e sovrascriva i metodi appropriati in modo che esponga gli elementi del Dizionario come se fossero elementi propri.

Per la cronaca, in .NET 4.6, il KeyCollection < T > implementa IReadOnlyCollection < T > , quindi se usi quell'interfaccia, puoi comunque riflettere le modifiche a il dizionario, contiene ancora O (1), e poiché l'interfaccia è covariante, puoi restituire IReadOnlyCollection < un tipo di base >

È brutto, ma lo farà

Dictionary<int,string> dict = new Dictionary<int, string>();
...
ReadOnlyCollection<int> roc = new ReadOnlyCollection<int>((new List<int>((IEnumerable<int>)dict.Keys)));
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top