知识点总结: c#,使用自定义类型来作为Dictionary的Key

来源:互联网 发布:javascript高级教程 编辑:程序博客网 时间:2024/05/29 19:34

首先来看一个变量的定义:

/// <summary>        /// key依次是StationId,channelId,deviceId,paraType,dataId,dataTypeId,logicalDeviceIndex,paraHandle,sourceId,value是paraName。读取PC_TB_35_07表后,再找到相应的SourceId后,保存到这里.保存的是定时记录        /// </summary>        private            Dictionary                <uint,                    Dictionary                        <uint, Dictionary<uint, Dictionary<int, Dictionary<int, Dictionary<int, Dictionary<int, Dictionary<int, Dictionary<int, string>>>>>                            >>>> m_PC_TB_35_07DatalogDic =                                new Dictionary                <uint,                    Dictionary                        <uint, Dictionary<uint, Dictionary<int, Dictionary<int, Dictionary<int, Dictionary<int, Dictionary<int, Dictionary<int, string>>>>>                            >>>>();

看不懂吧?看起来很困难吧。其实就是因为key有多个字段,但是写代码的人并没有想到可以使用使用自定义类型来作为key,所以就使用Dictionary套Dictionary的方式,这种方式会导致用的时候也很痛苦,例如,要一层一层的判断,这样就导致了每次使用,要做n次字典的查找,我数了一下,HasDatalog的一次调用,会导致17次的字典查找,实际上只需要一两次就够了。

public bool HasDatalog(uint stationId, uint channelId, uint deviceId)        {            if (!GetDatalogForChannel(stationId, channelId))                return false;            if (!m_PC_TB_35_07DatalogDic.ContainsKey(stationId))                return false;            if (!m_PC_TB_35_07DatalogDic[stationId].ContainsKey(channelId))                return false;            if (!m_PC_TB_35_07DatalogDic[stationId][channelId].ContainsKey(deviceId))                return false;            if (!m_PC_TB_35_07DatalogDic[stationId][channelId][deviceId].ContainsKey(1))                return false;            if (m_PC_TB_35_07DatalogDic[stationId][channelId][deviceId][1].Count == 0)                return false;            return true;                    }

所以考虑使用自定义结构来作为Dictionary的Key,示例代码如下,其实主要就是要让自定义类型实现IEqualityComparer接口,而这里面最关键的就是要实现GetHashCode,好在这个结构的字段不多,所以就参考一下《C#本质论(第三版)》p267的实现,大致的代码如下。


using System.Collections.Generic;namespace TestDictionary{     struct DatalogValue    {        public int paraHandle;        public int paraName;    }    struct DatalogKey : IEqualityComparer<DatalogKey>    {        public DatalogKey(uint dataId, uint dataTypeId, uint logicalDeviceIndex)        {            this.dataId = dataId;            this.dataTypeId = dataTypeId;            this.logicalDeviceIndex = logicalDeviceIndex;        }        public uint dataId;        public uint dataTypeId;        public uint logicalDeviceIndex;        public bool Equals(DatalogKey x, DatalogKey y)        {            return x.dataId == y.dataId &&                   x.dataTypeId == y.dataTypeId &&                    x.logicalDeviceIndex == y.logicalDeviceIndex;        }        public int GetHashCode(DatalogKey obj)        {            int hashCode = dataId.GetHashCode();            if (hashCode != dataTypeId.GetHashCode())                            hashCode ^= dataTypeId.GetHashCode();                                        if (hashCode != logicalDeviceIndex.GetHashCode())                hashCode ^= dataTypeId.GetHashCode();            return hashCode;        }    }}

测试:


using System;using System.Collections.Generic;using System.Windows.Forms;namespace TestDictionary{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();        }        private void button1_Click(object sender, EventArgs e)        {            Dictionary<DatalogKey, int> testDataLog = new Dictionary<DatalogKey, int>();            testDataLog.Add(new DatalogKey(1, 1, 1), 1);            testDataLog.Add(new DatalogKey(1, 2, 1), 2);            testDataLog.Add(new DatalogKey(1, 3, 1), 3);            testDataLog.Add(new DatalogKey(2, 1, 1), 4);            testDataLog.Add(new DatalogKey(2, 2, 1), 4);            MessageBox.Show(testDataLog[new DatalogKey(2, 1, 1)].ToString());            if(!testDataLog.ContainsKey(new DatalogKey(2,1,2)))                MessageBox.Show("no");        }    }}


0 0