如何获取字典中的键的ReadOnlyCollection

我的类包含Dictionary dict ,我想公开键的ReadOnlyCollection 。 如何在不将Dictionary.KeyCollection dict.Keys到数组然后将数组作为ReadOnlyCollection公开的情况下执行此操作?

我希望ReadOnlyCollection是一个合适的包装器,即。 反映基础字典中的变化,据我所知,将集合复制到数组将不会这样做(以及看似效率低下 – 我实际上并不想要一个新的集合,只是为了公开底层的密钥集合.. )。 任何想法将不胜感激!

编辑:我正在使用C#2.0,因此没有.ToList(轻松)可用的扩展方法。

如果你真的想使用ReadOnlyCollection ,问题是ReadOnlyCollection 的构造函数采用IList ,而Dictionary的KeyCollection只是ICollection

因此,如果要将KeyCollection包装在ReadOnlyCollection中,则必须创建一个适配器(或包装器)类型,实现IList ,包装KeyCollection。 所以它看起来像:

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

虽然不是很优雅,特别是因为KeyCollection已经是一个只读集合,你可以简单地传递它作为ICollection 🙂

DrJokepu说可能很难为Keys Collection实现一个包装器。 但是,在这种特殊情况下,我认为实现并不是那么困难,因为正如我们所知,这是一个只读包装器。

这允许我们忽略一些在其他情况下难以实现的方法。

这是Dictionary.KeyCollection的包装器的快速实现:

 class MyListWrapper : IList { private Dictionary.KeyCollection keys; public MyListWrapper(Dictionary.KeyCollection keys) { this.keys = keys; } #region IList Members public int IndexOf(T item) { if (item == null) throw new ArgumentNullException(); IEnumerator 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 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 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 Members public IEnumerator GetEnumerator() { return keys.GetEnumerator(); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return keys.GetEnumerator(); } #endregion } 

这可能不是这些方法的最佳实现:)但它只是为了certificate这可能已经完成。

假设您使用的是C#3.0并且您拥有:

字典 d;

然后

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

您还需要导入System.Linq命名空间。

遗憾的是,就我所知, KeyCollection不会暴露任何可以让你轻松完成此任务的内容。

但是,您可以将ReadOnlyCollection子类化,以便其构造函数接收字典本身并覆盖相应的方法,以便它将Dictionary的项目公开为它们自己的项目。

为了记录,在.NET 4.6中, KeyCollection实现了IReadOnlyCollection ,所以如果你使用那个接口,你仍然可以反映对字典的更改,仍然得到O(1)包含,并且因为接口是协变的,你可以返回IReadOnlyCollection

这很丑陋,但这样做会

 Dictionary dict = new Dictionary(); ... ReadOnlyCollection roc = new ReadOnlyCollection((new List((IEnumerable)dict.Keys)));