zoukankan      html  css  js  c++  java
  • 构建可反转排序的泛型字典类(6)实现IDictionary接口中的Keys和Values属性

     

    6. 实现IDictionary接口中的KeysValues属性

    现在我们可以着眼于IDictionary接口的实现。第4节中,专门针对这个接口做了一个最简化的例子,我们来回顾一下,它是怎么实现IDictionary接口中的KeysValues属性的。

    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;
            }

        }

     

    可以很清楚地看到,它把数组里的所有元素拷贝到另一块内存空间中并返回,这再一次带来了性能问题,如果频繁地访问KeysValues属性还会给垃圾回收带来压力。最好的解决办法当然是直接引用而不是拷贝数组里的元素,你还希望增加一些功能,可以使用索引访问Keys属性或Values属性所返回的ICollection。但从第5节中的图2(最好直接下载下来以方便观看)中可以看到ICollection接口只有寥寥几个成员,并没有Item属性,怎么办呢?当然是从ICollection的子接口中寻找合适的接口了。我们知道,ICollection接口是集合接口的基接口,而它的子接口则是更专用的集合接口,如IDictionary表示带有键\值对的集合,IList表示值的集合,它们都可以按索引访问。

    所以这一次你决定另外实现公有的KeysValues属性,并返回一个ILst<T>接口,并手动实现它,一方面满足所有的功能,另一方面也可以实现IDictionaryIDictionary<TKey, TValue>接口的KeysValues属性。好,先来看看ILst<T>接口的关系图:


     

    4  IList<T>接口关系图

    可以看到,实现它并不简单,好在我们将屏蔽所有对元素进行改动的功能。当然,首先还是要要实现一个枚举器(感觉又回到了第2节:http://cgbluesky.blog.163.com/blog/static/241235582008113103320661/ ),不同的地方在于,这次枚举器跟调用类的关系不再是嵌套关系,它们处于同一层次,都是ReversibleSortedList的嵌套类。另外由于引用外部类集合,这里也不需要考虑反向排序的问题。

    下面是Keys属性枚举时所需要的枚举器:

    ReversibleSortedListKeyEnumerator
     

    同理,Values属性枚举时所需要的枚举器代码类似:

    ReversibleSortedListValueEnumerator
     

    枚举器实现了,接下来实现Keys所需要的IList<T>。注意,这里通过弹出异常屏蔽了所有企图对元素进行修改的操作。

    KeyListK,V
     

    同理,Values所需要的Llist<T>代码相似:

    ValueList K, V definition
     

    上面两个IList<T>接口代码调用了外部类的一些方法,需要把它们添加到ReversibleSortedList类中:

    公有方法如下:

     //查找指定键索引
        public int IndexOfKey(TKey key)
        
    {

            
    if (key.Equals(null))
            
    {
                
    throw new ArgumentNullException("key");
            }

            
    int num1 = Array.BinarySearch<TKey>(this.keys, 0this._size, key,
                                                    
    this._sortDirectionComparer);
            
    if (num1 < 0)
            
    {
                
    return -1;
            }

            
    return num1;
        }

        
    //查找指定值索引
        public int IndexOfValue(TValue value)
        
    {
            
    return Array.IndexOf<TValue>(this.values, value, 0this._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;
        }

     

    写了这么多代码,终于可以实现KeysValues属性了。

    首先添加这两个属性所需的成员变量:

        private KeyList<TKey, TValue> keyList;
        
    private ValueList<TKey, TValue> valueList;
     

    然后实现KeysValues属性,以上这么多代码,就是为了这两个属性:

        public IList<TKey> Keys
        
    {
            
    get
            
    {
                
    return this.GetKeyListHelper();
            }

        }


        
    public IList<TValue> Values
        
    {
            
    get
            
    {
                
    return this.GetValueListHelper();
            }

        }

     

    看到这,你是不是有些不耐烦了,反正我是有这样的感觉了。但有一点你必须明白,FCL里的代码就是这么实现的。

    好,做了这么多工作,终于可以看看成果,测试一下是否可用了。在Main方法添加如下代码:

        static void Main()
        
    {
            ReversibleSortedList
    <intstring> rs = new ReversibleSortedList<intstring>();
            
    //添加元素
            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<intstring> 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()方法里的东西,尝试是否能通过KeysValues属性更改元素。

    ReversibleSortedList 0.5版本:实现KeysValues属性

    完整代码下载

    运行结果:

    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

  • 相关阅读:
    Ubuntu下Geary安装
    (1)html初步--表格的使用
    MYSQL笔记
    三,springboot集成mybatis
    一台服务部署多个tomcat注意事项
    Apache和Tomcat整合(一个Apache 不同域名处理多个不同业务)
    linux 安装 apache
    linux笔记
    关联查询一张小表。对性能有影响吗(mysql)
    关于mysql的临时表并行的问题
  • 原文地址:https://www.cnblogs.com/abatei/p/1071144.html
Copyright © 2011-2022 走看看