zoukankan      html  css  js  c++  java
  • 活用接口——反例:MultiKeyDictionary

        字典Dictionary<TKey, TValue>相信大家都用过,但是如果字典的键是一个TKey数组(或者IList<TKey>),怎么办?
        这就是今天要讨论的案例:MultiKeyDictionary<TKey, TValue>
        先来看看反例:
    public class MultiKeyDictionary<TKey, TValue> : IDictionary<TKey[], TValue>
    {
        
    private static readonly List<Type> COLUMNTYPELIST;
        
    private const string HASHCODECOLNAME = "HASHCODE";
        
    private const string KEYCOLMNFORMAT = "KEY{0}";
        
    private const int MAXPRIMARYKEYCOUNT = 0x1f;
        
    private int _keyCount;
        
    private DataTable _dataTable;
        
    private TKey _defaultKeyValue;
        
    private Dictionary<string, TValue> _hashTable;

        
    private MultiKeyDictionary()
        {
            
    this._keyCount = 0;
            
    this._dataTable = null;
            
    this._hashTable = null;
            
    this._defaultKeyValue = default(TKey);
            
    if (!MultiKeyDictionary<TKey, TValue>.COLUMNTYPELIST.Contains(typeof(TKey)))
            {
                
    throw new ArgumentException(""typeof(TKey).Name));
            }
        }

        
    public MultiKeyDictionary(int keyCount, TKey defaultKeyValue) : this()
        {
            
    if (keyCount <= 0)
            {
                
    throw new ArgumentOutOfRangeException("keyCount");
            }
            
    if (defaultKeyValue == null)
            {
                
    throw new ArgumentNullException("defaultKeyValue");
            }
            
    this._keyCount = keyCount;
            
    this._dataTable = this.CreateDataTable();
            
    this._hashTable = new Dictionary<string, TKey>();
            
    this._defaultKeyValue = defaultKeyValue;
        }

        
    public void Add(TKey[] keyList, TValue value)
        {
            
    if ((((keyList == null|| (keyList.Length > this._keyCount)) ? 1 : 0!= 0)
            {
                
    throw new ArgumentOutOfRangeException("keyList");
            }
            
    if (this.ContainsKey(aoKeyList))
            {
                
    throw new ArgumentException("");
            }
            DataRow dr 
    = this._dataTable.NewRow();
            
    for (int i = 0; i < this._keyCount; i++)
            {
                TKey key 
    = default(TKey);
                TKey value 
    = key;
                
    if (i < keyList.Length)
                {
                    value 
    = keyList[i];
                }
                
    else
                {
                    value 
    = this._defaultKeyValue;
                }
                dr[i] 
    = value;
            }
            
    string hashCode = Guid.NewGuid().ToString();
            dr[
    "HASHCODE"= hashCode;
            
    this._dataTable.Rows.Add(dr);
            
    this._hashTable.Add(hashCode, value);
        }
        
    //此处省去600行代码
    }
        第一次看到这个代码的时候,我也傻眼了,没想到这个给竟然能写成这样。里面用DataTable来放多个键值,并且,规定前面的每一个列是主键,到最后一 列,放一个Guid的ToString,然后再通过Dictionary<string, TValue>来查找对应的值。
        说说这么实现的不足之处吧(好像没什么必要。。。),第一用DataTable的话,效率将被极大的降低,第二,必须要预先告知数组的最大长度,如果,定多了影响性能,定少了,没法加数据。
        下面说说正确的实现方式吧。
        第一、MultiKeyDictionary<TKey, TValue>是Dictionary<TKey, TValue>的一种特例,相当于把Dictionary<TKey, TValue>中的TKey替换成TKey[],所以应该让MultiKeyDictionary<TKey, TValue>继承Dictionary<TKey[], TValue>。
        第二、剩下来的问题是,如何修改TKey[]的判等,如果Dictionary<TKey[], TValue>没有留下这个扩展,当然就没法直接利用继承了。看一下Dictionary<TKey, TValue>的构造函数,不难发现有一个public Dictionary(IEqualityComparer<TKey> comparer)的构造,IEqualityComparer<TKey>是个什么样的接口?它包含bool Equals(T x, T y);int GetHashCode(T obj);两个方法,也就是通过它,可以修改对象判等(包括GetHashCode)。
        第三、到这里,相信已经比较明确了,写一个类实现IEqualityComparer<TKey[]>接口,在构造 MultiKeyDictionary<TKey, TValue>时调用Dictionary<TKey[], TValue>的带参构造,将一个符合IEqualityComparer<TKey[]>接口的对象传入,就完成了一个这个 MultiKeyDictionary,并且,拥有所有Dictionary<TKey[], TValue>的功能,如果需要,还可以添加自己的成员。

        最后,有一个注意点,GetHashCode和Equals的相互关系:
        1、GetHashCode相等,对象未必Equals
        2、对象Equals,GetHashCode必定相等
        3、GetHashCode不相等,对象必定不Equals
        更具体的描述在MSDN


  • 相关阅读:
    docker-linux下的部署和基本命令
    Docker——Docker安装Sentinel
    分布式事务
    Git仓库完整迁移
    JWT token过期自动续期解决方案
    ORACLE用户的创建与授只读权
    Arthas-Java的线上问题定位工具
    mysql读写分离
    redis集群搭建-3.0/4.0版本
    相信自己,只要你努力了,你的梦想就可以实现
  • 原文地址:https://www.cnblogs.com/vwxyzh/p/782497.html
Copyright © 2011-2022 走看看