Pergunta

Meu classe contém um Dictionary<T, S> dict, e eu quero expor um ReadOnlyCollection<T> das chaves. Como posso fazer isso sem copiar o Dictionary<T, S>.KeyCollection dict.Keys para uma matriz e, em seguida, expondo a matriz como uma ReadOnlyCollection?

Eu quero o ReadOnlyCollection ser um invólucro próprio, ie. para refletir as mudanças no dicionário subjacente, e como eu o entendo copiar a coleção para uma matriz não vai fazer isso (assim como parecendo ineficiente - Eu realmente não quero uma nova coleção, apenas para expor a coleção subjacente de chaves .. .). Alguma idéia seria muito apreciada!

Edit: eu estou usando C # 2.0, portanto, não têm métodos de extensão, como .ToList (facilmente) disponíveis.

Foi útil?

Solução

Se você realmente quiser usar ReadOnlyCollection , o problema é que o construtor de ReadOnlyCollection leva um IList , enquanto o KeyCollection do dicionário é apenas uma ICollection .

Então, se você quer envolver o KeyCollection em um ReadOnlyCollection, você terá que criar um tipo de adaptador (ou invólucro), a implementação de IList , envolvendo o KeyCollection. Por isso, seria algo como:

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

Não é muito elegante, porém, especialmente como o KeyCollection é já uma coleção somente leitura, e que você poderia simplesmente passá-lo em torno de como um ICollection :)

Outras dicas

DrJokepu disse que poderia ser difícil de implementar um wrapper para Chaves Collection. Mas, neste caso particular, eu acho que a implementação não é tão difícil, porque, como sabemos, este é um wrapper somente leitura.

Isso nos permite ignorar alguns métodos que, em outro caso, seria difícil de implementar.

Aqui está uma rápida implementação do wrapper 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
}

Isto pode não ser a melhor implementação para esses métodos :) mas foi apenas para provar que isso pode ser feito.

Supondo que você estiver usando C # 3.0 e você tem:

dicionário d;

Em seguida

ReadOnlyCollection r = novo ReadOnlyCollection (d.Keys.ToList ());

Você também vai precisar para importar o namespace System.Linq.

Infelizmente não é possível para que direcly, tanto quanto eu sei como KeyCollection<T> não expõe qualquer coisa que lhe permitiria fazer isso facilmente.

Você pode, no entanto, subclasse ReadOnlyCollection<T> para que seu construtor recebe o dicionário próprio e substituir os métodos adequados para que ele expõe os itens do dicionário como se fossem seus próprios itens.

Para o registro, em .NET 4.6, o KeyCollection<T> implementos IReadOnlyCollection<T>, por isso, se você usar essa interface, você ainda pode refletir mudanças no dicionário, ainda obter O (1) contém, e porque a interface é covariant, você pode retorno IReadOnlyCollection<some base type>

É feio, mas isso vai fazê-lo

Dictionary<int,string> dict = new Dictionary<int, string>();
...
ReadOnlyCollection<int> roc = new ReadOnlyCollection<int>((new List<int>((IEnumerable<int>)dict.Keys)));
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top