6. 實現IDictionary接口中的Keys和Values屬性
現在我們可以著眼於IDictionary接口的實現。第4節中,專門針對這個接口做了一 個最簡化的例子,我們來回顧一下,它是怎麼實現IDictionary接口中的Keys和Values屬性的。
public ICollection Keys
{ //返回所有鍵的集合
get
{ //把所有鍵的集合拷貝到新數組中並返回
Object[] keys = new Object[ItemsInUse];
for (Int32 n = 0; n < ItemsInUse; n++)
keys[n] = items[n].Key;
return keys;
}
}
public ICollection Values
{ //返回 所有值的集合
get
{ //把所有值的集合拷貝到新數組中並返回
Object[] values = new Object[ItemsInUse];
for (Int32 n = 0; n < ItemsInUse; n++)
values[n] = items [n].Value;
return values;
}
}
可以很清楚地看到,它把數組裡的所有元素拷貝 到另一塊內存空間中並返回,這再一次帶來了性能問題,如果頻繁地訪問Keys和Values屬性還會給垃圾回收帶來壓力。最好的解決辦法當然是 直接引用而不是拷貝數組裡的元素,你還希望增加一些功能,可以使用索引訪問Keys屬性或Values屬性所返回的ICollection。但從第5節中的 圖2(最好直接下載下來以方便觀看)中可以看到ICollection接口只有寥寥幾個成員,並沒有Item屬性,怎麼辦呢?當然是從ICollection的子 接口中尋找合適的接口了。我們知道,ICollection接口是集合接口的基接口,而它的子接口則是更專用的集合接口,如IDictionary表示帶有鍵\值對的集合,IList表示值的集合,它們都可以按索引訪問。
所以這一次你決定另外實現公有的Keys和Values屬性,並返回一個 ILst<T>接口,並手動實現它,一方面滿足所有的功能,另一方面也可以實現IDictionary和IDictionary<TKey, TValue>接口的 Keys和Values屬性。好,先來看看ILst<T>接口的關系圖:
圖4 IList<T>接口關系圖
可以看到,實現它 並不簡單,好在我們將屏蔽所有對元素進行改動的功能。當然,首先還是要要實現一個枚舉器(感覺又回到了第2節: http://cgbluesky.blog.163.com/blog/static/241235582008113103320661/ ),不同的地方在於,這次枚舉器跟調用類的關系不再是嵌套關 系,它們處於同一層次,都是ReversibleSortedList的嵌套類。另外由於引用外部類集合,這裡也不需要考慮反向排序的問題。
下面是 Keys屬性枚舉時所需要的枚舉器:
#region ReversibleSortedListKeyEnumerator
private sealed class ReversibleSortedListKeyEnumerator :
IEnumerator<TKey>, IDisposable, IEnumerator
{
// 成員變量
private ReversibleSortedList<TKey, TValue> _ReversibleSortedList;
private TKey currentKey; //記錄當前值
private int index; //記錄當前索引
private int version; //記錄此類創建時, 外部類的版本號
//構造方法
internal ReversibleSortedListKeyEnumerator(
ReversibleSortedList<TKey, TValue> ReversibleSortedList)
{ //傳遞外部類元素所在集合的引用
this._ReversibleSortedList = ReversibleSortedList;
this.version = ReversibleSortedList.version;
}
public void Dispose()
{
this.index = 0;
this.currentKey = default(TKey);
}
public bool MoveNext()
{
if (this.version != this._ReversibleSortedList.version)
{
throw new InvalidOperationException(
"枚舉版本檢查錯誤");
}
if (this.index < this._ReversibleSortedList.Count)
{
this.currentKey = this._ReversibleSortedList.keys [this.index];
this.index++;
return true;
}
this.index = this._ReversibleSortedList.Count + 1;
this.currentKey = default(TKey);
return false;
}
void IEnumerator.Reset()
{
if (this.version != this._ReversibleSortedList.version)
{
throw new InvalidOperationException(
"枚舉版本檢查錯誤");
}
this.index = 0;
this.currentKey = default(TKey);
}
// 屬性
public TKey Current
{
get
{
return this.currentKey;
}
}
object IEnumerator.Current
{
get
{
if ((this.index == 0) || (this.index ==
(this._ReversibleSortedList.Count + 1)))
{
throw new InvalidOperationException(
"不能進行枚舉操作");
}
return this.currentKey;
}
}
}
#endregion
同理,Values屬性枚舉時所需要的枚舉器代碼類似:
ReversibleSortedListValueEnumerator#region ReversibleSortedListValueEnumerator
private sealed class ReversibleSortedListValueEnumerator :
IEnumerator<TValue>, IDisposable, IEnumerator
{
// 成員變量
private ReversibleSortedList<TKey, TValue> _ReversibleSortedList;
private TValue currentValue;
private int index;
private int version;
internal ReversibleSortedListValueEnumerator(
ReversibleSortedList<TKey, TValue> ReversibleSortedList)
{
this._ReversibleSortedList = ReversibleSortedList;
this.version = ReversibleSortedList.version;
}
public void Dispose()
{
this.index = 0;
this.currentValue = default(TValue);
}
public bool MoveNext()
{
if (this.version != this._ReversibleSortedList.version)
{
throw new InvalidOperationException(
"Enumeration failed version check");
}
if (this.index < this._ReversibleSortedList.Count)
{
this.currentValue = this._ReversibleSortedList.values[this.index];
this.index++;
return true;
}
this.index = this._ReversibleSortedList.Count + 1;
this.currentValue = default (TValue);
return false;
}
void IEnumerator.Reset()
{
if (this.version != this._ReversibleSortedList.version)
{
throw new InvalidOperationException(
"Enumeration failed version check");
}
this.index = 0;
this.currentValue = default(TValue);
}
// 屬性
public TValue Current
{
get
{
return this.currentValue;
}
}
object IEnumerator.Current
{
get
{
if ((this.index == 0) || (this.index ==
(this._ReversibleSortedList.Count + 1)))
{
throw new InvalidOperationException (
"Enumeration operation could not occur");
}
return this.currentValue;
}
}
}
#endregion
枚舉器實現了, 接下來實現Keys所需要的IList<T>。注意,這裡通過彈出異常屏蔽了所有企圖對元素進行修改的操作。
KeyListK,V#region KeyList<K,V>
private sealed class KeyList<K, V> : IList<K>, ICollection<K>,
IEnumerable<K>, ICollection, IEnumerable
{
// 成員變量
private ReversibleSortedList<K, V> _dict;
//成員方法
internal KeyList(ReversibleSortedList<K, V> dictionary)
{
this._dict = dictionary;
}
public void Add(K key)
{
throw new NotSupportedException("不支持Add操作");
}
public void Clear()
{
throw new NotSupportedException("不支持Clear操作");
}
public bool Contains(K key)
{
return this._dict.ContainsKey(key);
}
public void CopyTo(K[] array, int arrayIndex)
{
Array.Copy(this._dict.keys, 0, array, arrayIndex, this._dict.Count);
}
public IEnumerator<K> GetEnumerator()
{
return new
ReversibleSortedList<K, V>.ReversibleSortedListKeyEnumerator(
this._dict);
}
public int IndexOf(K key)
{
if (key == null)
{
throw new ArgumentNullException("key");
}
int num1 = Array.BinarySearch<K>(this._dict.keys, 0,
this._dict.Count, key,
this._dict._sortDirectionComparer);
if (num1 >= 0)
{
return num1;
}
return -1;
}
public void Insert(int index, K value)
{
throw new NotSupportedException("不支持Insert操作");
}
public bool Remove(K key)
{
return false;
}
public void RemoveAt(int index)
{
throw new NotSupportedException("不支持RemoveAt操作");
}
void ICollection.CopyTo(Array array, int arrayIndex)
{
if ((array != null) && (array.Rank != 1))
{
throw new ArgumentException(
"不支 持多維數組");
}
try
{
Array.Copy (this._dict.keys, 0, array, arrayIndex,
this._dict.Count);
}
catch (ArrayTypeMismatchException atme)
{
throw new ArgumentException("錯誤的數 組類型", atme);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return new
ReversibleSortedList<K, V>.ReversibleSortedListKeyEnumerator(
this._dict);
}
// 屬性
public int Count
{
get
{
return this._dict._size;
}
}
public bool IsReadOnly
{
get
{
return true;
}
}
public K this[int index]
{
get
{
return this._dict.GetKey(index);
}
set
{
throw new NotSupportedException("不支持通過索引進行更改的操作");
}
}
bool ICollection.IsSynchronized
{
get
{
return false;
}
}
object ICollection.SyncRoot
{
get
{
return this._dict;
}
}
}
#endregion
同理 ,Values所需要的Llist<T>代碼相似:
ValueList K, V definition#region ValueList <K, V> definition
private sealed class ValueList<K, V> : IList<V>, ICollection<V>,
IEnumerable<V>, ICollection, IEnumerable
{
// 成員變量
private ReversibleSortedList<K, V> _dict;
// 成員方法
internal ValueList(ReversibleSortedList<K, V> dictionary)
{
this._dict = dictionary;
}
public void Add(V key)
{
throw new NotSupportedException("不支持Add操作");
}
public void Clear()
{
throw new NotSupportedException("不支持Clear操作");
}
public bool Contains(V value)
{
return this._dict.ContainsValue(value);
}
public void CopyTo(V[] array, int arrayIndex)
{
Array.Copy(this._dict.values, 0, array, arrayIndex, this._dict.Count);
}
public IEnumerator<V> GetEnumerator()
{
return new
ReversibleSortedList<K, V>.ReversibleSortedListValueEnumerator(
this._dict);
}
public int IndexOf(V value)
{
return Array.IndexOf<V>(this._dict.values, value, 0, this._dict.Count);
}
public void Insert(int index, V value)
{
throw new NotSupportedException("不支持Insert操作");
}
public bool Remove(V value)
{
return false;
}
public void RemoveAt(int index)
{
throw new NotSupportedException("不支持RemoveAt操作");
}
void ICollection.CopyTo(Array array, int arrayIndex)
{
if ((array != null) && (array.Rank != 1))
{
throw new ArgumentException(
"不支持多維數組");
}
try
{
Array.Copy(this._dict.values, 0, array, arrayIndex,
this._dict.Count);
}
catch (ArrayTypeMismatchException atme)
{
throw new ArgumentException ("錯誤的數組類型", atme);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return new
ReversibleSortedList<K, V>.ReversibleSortedListValueEnumerator(
this._dict);
}
// 屬性
public int Count
{
get
{
return this._dict._size;
}
}
public bool IsReadOnly
{
get
{
return true;
}
}
public V this[int index]
{
get
{
return this._dict.GetByIndex(index);
}
set
{
throw new NotSupportedException("不支持通過索引改變元素值");
}
}
bool ICollection.IsSynchronized
{
get
{
return false;
}
}
object ICollection.SyncRoot
{
get
{
return this._dict;
}
}
}
#endregion
上面兩個IList<T>接口代碼調用了外部類的一些方法,需要把它們添加到ReversibleSortedList 類中:
公有方法如下:
//查找指定鍵索引
public int IndexOfKey(TKey key)
{
if (key.Equals(null))
{
throw new ArgumentNullException("key");
}
int num1 = Array.BinarySearch<TKey>(this.keys, 0, this._size, key,
this._sortDirectionComparer);
if (num1 < 0)
{
return -1;
}
return num1;
}
//查找指定值索引
public int IndexOfValue(TValue value)
{
return Array.IndexOf<TValue>(this.values, value, 0, this._size);
}
//判斷是否包含指定鍵
public bool ContainsKey(TKey key)
{
return (this.IndexOfKey(key) >= 0);
}
// 判斷是否包含指定值
public bool ContainsValue(TValue value)
{
return (this.IndexOfValue(value) >= 0);
}
私有方法如下:
private TValue GetByIndex(int index)
{
if ((index < 0) || (index >= this._size))
{
throw new ArgumentOutOfRangeException ("index", "Index out of range");
}
return this.values[index];
}
//返回指定索引的鍵
private TKey GetKey(int index)
{
if ((index < 0) || (index >= this._size))
{
throw new ArgumentOutOfRangeException("index", "Index out of range");
}
return this.keys[index];
}
private void Insert(int index, TKey key, TValue value)
{ //在指定索引入插入數據
if (this._size == this.keys.Length)
{
this.EnsureCapacity(this._size + 1);
}
if (index < this._size)
{ //當 插入元素不是添加在未尾時,移動插入點後面的元素
Array.Copy(this.keys, index, this.keys, (int)(index + 1),
(int)(this._size - index));
Array.Copy(this.values, index, this.values, (int)(index + 1),
(int)(this._size - index));
}
this.keys[index] = key; //在插入點 插入鍵
this.values[index] = value; //在插入點插入值
this._size++;
this.version++;
}
private KeyList<TKey, TValue> GetKeyListHelper()
{ //獲取鍵的IList<T>集合
if (this.keyList == null)
{
this.keyList = new KeyList<TKey, TValue>(this);
}
return this.keyList;
}
private ValueList<TKey, TValue> GetValueListHelper()
{ //獲取值的IList<T>集合
if (this.valueList == null)
{
this.valueList = new ValueList<TKey, TValue>(this);
}
return this.valueList;
}
寫了這麼 多代碼,終於可以實現Keys和Values屬性了。
首先添加這兩個屬性所需的成員變量:
private KeyList<TKey, TValue> keyList;
private ValueList<TKey, TValue> valueList;
然後實現Keys和Values屬性,以上這麼多代碼,就是為了這兩 個屬性:
public IList<TKey> Keys
{
get
{
return this.GetKeyListHelper();
}
}
public IList<TValue> Values
{
get
{
return this.GetValueListHelper();
}
}
看到這,你是不是有些不 耐煩了,反正我是有這樣的感覺了。但有一點你必須明白,FCL裡的代碼就是這麼實現的。
好,做了這麼多工作,終於可以看看成果, 測試一下是否可用了。在Main方法添加如下代碼:
static void Main()
{
ReversibleSortedList<int, string> rs = new ReversibleSortedList<int, string>();
//添加元素
rs.Add(3, "a");
rs.Add(1, "b");
rs.Add(2, "c");
rs.Add(6, "d");
rs.Add(5, "e");
rs.Add(4, "f");
//打印鍵 /值
foreach (KeyValuePair<int, string> d in rs)
{
Console.WriteLine(d.Key + " " + d.Value);
}
//打印鍵,這裡訪問了Keys屬性
foreach (int i in rs.Keys)
{
Console.Write(i + " ");
}
Console.WriteLine();// 換行
//打印值,這裡訪問了Values屬性
foreach (string s in rs.Values)
{
Console.Write(s + " ");
}
Console.WriteLine();//換行
Console.WriteLine (rs.Keys[3]); //通過索引訪問鍵
Console.WriteLine(rs.Values[4]); //通過索引訪問值
}
上帝啊 !太痛苦了,如果你也有這樣的感覺,請下載現成的代碼,更改Main()方法裡的東西,嘗試是否能通過Keys和Values屬性更改元素。
ReversibleSortedList 0.5版本:實現Keys和Values屬性
運行結果:
1 b
2 c
3 a
4 f
5 e
6 d
1 2 3 4 5 6
b c a f e d
4
e
本文配套源碼