Как получить доступную для чтения коллекцию<T> ключей в словаре<T, S="">
-
08-07-2019 - |
Вопрос
Мой класс содержит 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)));