Pregunta

Mi clase contiene un Diccionario < T, S > dict , y quiero exponer una ReadOnlyCollection < T > de las teclas. ¿Cómo puedo hacer esto sin copiar el Dictionary < T, S > .KeyCollection dict.Keys en una matriz y luego exponer la matriz como ReadOnlyCollection ?

Quiero que ReadOnlyCollection sea un contenedor adecuado, es decir. para reflejar los cambios en el Diccionario subyacente, y según tengo entendido, copiar la colección en una matriz no hará esto (además de parecer ineficiente, en realidad no quiero una nueva colección, solo para exponer la colección subyacente de claves ... .). Cualquier idea sería muy apreciada!

Editar: estoy usando C # 2.0, así que no tengo métodos de extensión como .ToList (fácilmente) disponibles.

¿Fue útil?

Solución

Si realmente quiere usar ReadOnlyCollection < T > ;, el problema es que el constructor de ReadOnlyCollection < T > toma una IList < T > ;, mientras que KeyCollection of the Dictionary es solo una ICollection < T > ;.

Por lo tanto, si desea ajustar KeyCollection en ReadOnlyCollection, deberá crear un tipo de adaptador (o contenedor), implementando IList < T > ;, ajustando KeyCollection. Entonces se vería así:

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

Sin embargo, no es muy elegante, especialmente porque KeyCollection ya es una colección de solo lectura, y que simplemente podría pasar como ICollection < T > :)

Otros consejos

DrJokepu dijo que podría ser difícil implementar un contenedor para Keys Collection. Pero, en este caso particular, creo que la implementación no es tan difícil porque, como sabemos, este es un contenedor de solo lectura.

Esto nos permite ignorar algunos métodos que, en otro caso, serían difíciles de implementar.

Aquí hay una implementación rápida del contenedor para 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
}

Esta podría no ser la mejor implementación para estos métodos :) pero fue solo para probar que esto podría hacerse.

Suponiendo que está utilizando C # 3.0 y tiene:

Diccionario < T, S > d;

Entonces

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

También deberá importar el espacio de nombres System.Linq.

Lamentablemente, no puede hacerlo directamente, por lo que yo sé, ya que KeyCollection < T > no expone nada que le permita hacer esto fácilmente.

Podría, sin embargo, subclase ReadOnlyCollection < T > para que su constructor reciba el diccionario y anule los métodos apropiados para que exponga los elementos del Diccionario como si fueran sus propios elementos.

Para el registro, en .NET 4.6, KeyCollection < T > implementa IReadOnlyCollection < T > , de modo que si usa esa interfaz, aún puede reflejar los cambios en el diccionario, todavía obtiene O (1) contiene, y debido a que la interfaz es covariante, puede devolver IReadOnlyCollection < algún tipo de base >

Es feo, pero esto lo hará

Dictionary<int,string> dict = new Dictionary<int, string>();
...
ReadOnlyCollection<int> roc = new ReadOnlyCollection<int>((new List<int>((IEnumerable<int>)dict.Keys)));
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top