zoukankan      html  css  js  c++  java
  • 构建可反转排序的泛型字典类(7)实现IDictionary接口

     

    7. 实现IDictionary接口

    前面做了很多努力,现在终于可以实现IDictionary接口了。当然,之所以要先实现它,目的之一还是为了之前留下的一点遗憾:在foreach中使用DictionaryEntry访问集合中的元素。

    需要注意,由于ReversibleSortedList类最主要的接口是泛型IDictionary接口,实现非泛型IDictionary接口主要是考虑到兼容性,试想,你的项目是用.NET 1.0实现的,但现在你需要使用.NET 2.0继续完善程序并使用到了一些.NET 2.0所独有的功能。但你并不想更改之前曾写好并稳定运行了很久的程序,此时,兼容是非常重要的。,IDictionary接口成员大部份是显式接口成员实现。这一节请对照第5节的图2观看,最好下载用图片浏览器打开,我们先改变ReversibleSortedList类的声明,加上IDictionary


    public class ReversibleSortedList<TKey, TValue> :
        IDictionary, IEnumerable
    <KeyValuePair<TKey, TValue>>, ICollection, IEnumerable
     

    ICollection接口开始实现:

    由于它的Count属性只是指示一个整数,可以和ICollection<KeyValuePain<TKey, TVlaue>>共用,并且前面已经实现了它,所以无需再另外实现。剩下的就只是IsSynchnonisedSyncRoot属性和CopyTo方法了,但CopyTo方法ICollection<KeyValuePain<TKey, TVlaue>>接口中也有,在MSDN中查看两个方法的定义:

    ICollection中的是:

    void CopyTo(    Array array,    int index)

    ICollection<KeyValuePain<TKey, TVlaue>>中的是

    void CopyTo(T[] array, int arrayIndex)

    可以看到array参数并不一样,一个是泛型,一个是数组,所以需要为这个方法实现两个版本,当然,我们先实现的是ICollection接口中的CopyTo方法:

    void ICollection.CopyTo(Array array, int arrayIndex)
        {
            
    if (array == null)
            {
                
    throw new ArgumentNullException("array");
            }
            
    if (array.Rank != 1)
            {
                
    throw new ArgumentException(
                    
    "不支持多维数组拷贝");
            }
            
    if (array.GetLowerBound(0!= 0)
            {   
    //检查参数数组是否下限为
                throw new ArgumentException("A non-zero lower bound was provided");
            }
            
    if ((arrayIndex < 0|| (arrayIndex > array.Length))
            {   
    //检查参数数组容量
                throw new ArgumentOutOfRangeException(
                    
    "arrayIndex""Need non negative number");
            }
            
    if ((array.Length - arrayIndex) < this.Count)
            {   
    //检查参数数组容量
                throw new ArgumentException("Array plus the offset is too small");
            }
            
    //把参数array强制转换为KeyValuePair<TKey, TValue>数组类型
            KeyValuePair<TKey, TValue>[] pairArray1 =
                 array 
    as KeyValuePair<TKey, TValue>[];
            
    if (pairArray1 != null)
            {   
    //如果转换成功,则拷贝数据
                for (int num1 = 0; num1 < this.Count; num1++)
                {
                    pairArray1[num1 
    + arrayIndex] =
                        
    new KeyValuePair<TKey, TValue>(this.keys[num1],
                        
    this.values[num1]);
                }
            }
            
    else
            {   
    //如果转换不成功,则把参数array强制转化为object数组
                object[] objArray1 = array as object[];
                
    if (objArray1 == null)
                {
                    
    throw new ArgumentException("错误的数组类型");
                }
                
    try
                {
                    
    for (int num2 = 0; num2 < this.Count; num2++)
                    {
                        objArray1[num2 
    + arrayIndex] =
                               
    new KeyValuePair<TKey, TValue>(this.keys[num2],
                                                                    
    this.values[num2]);
                    }
                }
                
    catch (ArrayTypeMismatchException)
                {
                    
    throw new ArgumentException("错误的数组类型");
                }
            }
        }
     

    下面实现了ICollection接口的两个私有属性:

    bool ICollection.IsSynchronized
        {
            
    get
            {
                
    return false;
            }
        }
        
    object ICollection.SyncRoot
        {
            
    get
            {
                
    return this;
            }
        }
    好,现在开始正式实现IDictionary接口。首先是属性:
        
    bool IDictionary.IsFixedSize
        {
            
    get
            {
                
    return false;
            }
        }
        
    bool IDictionary.IsReadOnly
        {
            
    get
            {
                
    return false;
            }
        }
        
    //item属性,本质上就是索引器
        object IDictionary.this[object key]
        {
            
    get
            {
                
    if (ReversibleSortedList<TKey, TValue>.IsCompatibleKey(key))
                {
                    
    int num1 = this.IndexOfKey((TKey)key);
                    
    if (num1 >= 0)
                    {
                        
    return this.values[num1];
                    }
                }
                
    return null;
            }
            
    set
            {
                ReversibleSortedList
    <TKey, TValue>.VerifyKey(key);
                ReversibleSortedList
    <TKey, TValue>.VerifyValueType(value);
                
    //这里调用了IDictionary<TKey, TValue>接口的Item属性,由于
                
    //还没有实现它,所以先把这句屏敝掉
                
    //this[(TKey)key] = (TValue)value;
            }
        }
        ICollection IDictionary.Keys
        {
            
    get
            {
                
    return this.GetKeyListHelper();
            }
        }
        ICollection IDictionary.Values
        {
            
    get
            {
                
    return this.GetValueListHelper();
            }
        }

     

    首先注意,全部使用了显式接口成员实现,也就是说,只能通过接口调用这些方法。另外它的Item属性调用了还未实现的IDictionary<TKey, TValue>接口的Item属性:

    this[(TKey)key] = (TValue)value;

    所以需要先把这句屏蔽掉,等最后再释放出来。另外调用了两个新的私有方法,也需要加进去:


    private static void VerifyKey(object key)
        {   
    //检查key类型是否兼容TKey
            if (key.Equals(null))
            {
                
    throw new ArgumentNullException("key");
            }
            
    if (!(key is TKey))
            {   
    //检查key是否和TKey兼容。注意,此时TKey已经被替换为实际类型
                throw new ArgumentException(
                    
    "参数类型错误""key");
            }
        }
        
    private static void VerifyValueType(object value)
        {   
    //检查value类型
            if (!(value is TValue) && ((value != null|| typeof(TValue).IsValueType))
            {
                
    throw new ArgumentException(
                    
    "参数类型错误""value");
            }
        }
     

    VerifyValueType方法进行类型检查时有一个奇怪的判断,这一点主要是针对C#2.0的可空类型而设的。也就是说,在这里,空的值类型是合法的。关于可空类型,可以参考:

    http://cgbluesky.blog.163.com/blog/static/24123558200811112926423/

    下面,就剩下IDictionary接口成员方法没有实现了。其中,由于Clear()方法同时为IDictionaryICollection <KeyValuePair<TKey, TValue>>的成员方法,但两者的返回值和参数完全相同,所以可以共用一个拷贝:

     public void Clear()
        {
            
    this.version++;
            Array.Clear(
    this.keys, 0this._size);
            Array.Clear(
    this.values, 0this._size);
            
    this._size = 0;
        }
     

    剩下的全部为显式接口成员实现:

     void IDictionary.Add(object key, object value)
        {   
    //做类型检查再添加
            ReversibleSortedList<TKey, TValue>.VerifyKey(key);
            ReversibleSortedList
    <TKey, TValue>.VerifyValueType(value);
            
    this.Add((TKey)key, (TValue)value);
        }
        
    bool IDictionary.Contains(object key)
        {
            
    if (ReversibleSortedList<TKey, TValue>.IsCompatibleKey(key))
            {
                
    return this.ContainsKey((TKey)key);
            }
            
    return false;
        }
        IDictionaryEnumerator IDictionary.GetEnumerator()
        {
            
    return new ReversibleSortedList<TKey, TValue>.Enumerator<TKey, TValue>(
                    
    this);
        }
        
    void IDictionary.Remove(object key)
        {
            
    if (ReversibleSortedList<TKey, TValue>.IsCompatibleKey(key))
            {  
    //这里调用了IDictionary<TKey, TValue>接口的Remove方法,由于
               
    //还没有实现它,所以先把这句屏敝掉
               
    // this.Remove((TKey)key);
            }
        }

     

    上面代码调用了IsCompatibleKey(key)方法,需要把它加上去:


     private static bool IsCompatibleKey(object key)
        {   
    //用于检查键的类型并返回一个bool值
            if (key.Equals(null))
            {   
                
    throw new ArgumentNullException("key");
            }
            
    return (key is TKey);
        }
     

    其中,IDictionaryEnumerator IDictionary.GetEnumerator()方法是我们期待已久的,实现了它就可以在foreach中使用DictionaryEntry访问集合中的元素。另外Remove方法调用了IDictionary<TKey, TValue>接口的Remove方法。当然,我们还未实现它,这是第二次这样了,看样子还是首先应该实现泛型接口再实现非泛型接口。教训惨痛啊!写了这么多,懒得改了,大家知道就行了。

    好!终于完成了,现在终于可以看看成果了。改变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");
            
    //使用DictionaryEntry打印键/值
            foreach (DictionaryEntry d in (IDictionary)rs)
            {
                Console.WriteLine(d.Key 
    + "    " + d.Value);
            }
    }

     

    ReversibleSortedList 0.6版本:实现IDictionary接口

    完整代码下载

    运行结果:

    1   b

    2   c

    3   a

    4   f

    5   e

    6   d

    很遗憾,由于IDictionary.GetEnumerator()是显式接口成员实现,只能使用接口调用。接下来,终于可以实现最重要的一个接口IDictionary<TKey, TValue>了。

  • 相关阅读:
    算法导论第三版第二章第三节习题答案
    算法导论第三版第二章第二节习题答案
    Android各版本 内外卡真实路径
    Go语言 爬虫2编码转换
    gotour的安装
    算法导论第三版第二章思考题答案
    Go语言的日志记录功能
    算法导论 中 lg 的底数是2的原因相关文章
    Go语言 爬虫1网络请求
    SharePoint 2013 母版页修改后,无法添加应用程序
  • 原文地址:https://www.cnblogs.com/abatei/p/1071832.html
Copyright © 2011-2022 走看看