Как получить доступную для чтения коллекцию<T> ключей в словаре<T, S="">

StackOverflow https://stackoverflow.com/questions/284090

Вопрос

Мой класс содержит Dictionary<T, S> dict, и я хочу разоблачить ReadOnlyCollection<T> из ключей.Как я могу это сделать, не копируя Dictionary<T, S>.KeyCollection dict.Keys в массив, а затем выставляет массив в виде ReadOnlyCollection?

Я хочу, чтобы ReadOnlyCollection быть правильной оболочкой, т.е.чтобы отразить изменения в базовом словаре, и, насколько я понимаю, копирование коллекции в массив не приведет к этому (а также кажется неэффективным - на самом деле я не хочу новую коллекцию, просто чтобы предоставить базовую коллекцию ключей ...).Любые идеи будут высоко оценены!

Редактировать:Я использую C # 2.0, поэтому у меня нет таких методов расширения, как .ToList (легко) доступен.

Это было полезно?

Решение

Если вы действительно хотите использовать ReadOnlyCollection < T >, проблема заключается в том, что конструктор ReadOnlyCollection < T > принимает IList < T > ;, а KeyCollection словаря является только ICollection < T >.

Поэтому, если вы хотите обернуть KeyCollection в ReadOnlyCollection, вам нужно будет создать тип адаптера (или оболочки), реализующий IList < T >, обертывающий KeyCollection. Так это будет выглядеть так:

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

Не очень элегантно, тем более что KeyCollection уже является коллекцией только для чтения, и вы можете просто передать ее как ICollection < T > :)

Другие советы

DrJokepu сказал, что может быть сложно реализовать обертку для Keys Collection. Но, в данном конкретном случае, я думаю, что реализация не так сложна, потому что, как мы знаем, это оболочка только для чтения.

Это позволяет нам игнорировать некоторые методы, которые в другом случае было бы трудно реализовать.

Вот краткая реализация оболочки для 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
}

Возможно, это не лучшая реализация для этих методов :), но это просто для того, чтобы доказать, что это может быть сделано.

Предполагая, что вы используете C # 3.0 и у вас есть:

Словарь< T, S > d;

Тогда

Readonlyколлекция< T > r = новая коллекция для чтения< T >(d.Ключи.ToList() );

Вам также потребуется импортировать System.Пространство имен Linq.

К сожалению, вы не можете так прямо, насколько мне известно, поскольку KeyCollection < T > не предоставляет ничего, что позволило бы вам сделать это легко.

Однако вы можете создать подкласс ReadOnlyCollection < T > , чтобы его конструктор получал сам словарь и переопределял соответствующие методы, чтобы он представлял элементы словаря, как если бы они были его собственными элементами.

Для записи в .NET 4.6 KeyCollection < T > реализует IReadOnlyCollection < T > , поэтому если вы используете этот интерфейс, вы все равно можете отразить изменения в словарь, все еще get O (1) содержит, и, поскольку интерфейс ковариантен, вы можете вернуть IReadOnlyCollection < некоторый базовый тип >

Это некрасиво, но это сделает это

Dictionary<int,string> dict = new Dictionary<int, string>();
...
ReadOnlyCollection<int> roc = new ReadOnlyCollection<int>((new List<int>((IEnumerable<int>)dict.Keys)));
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top