您的位置:首页 > 其它

Struct vs Class 作为HashTable或者Dictionary的Key

2016-05-23 15:35 330 查看
1. 使用Struct.

     1) 使用Struct,如果成员都是简单类型,默认情况下,第一个成员相同的时候,GetHashCode 值相同。如果成员值全部相同,则两个Struct相等。

      2) Struct 因为要使用到反射,GetHashCode 和Equals效率比较低

2. 使用Class

    1)  必须实现GetHashCode,重载Equals方法(不然每次new 一个Class作为查找Key, HashCode都不一样)。最好是实现IEquatable<ConfigCacheKeyClass>接口,以避免装箱。

     2)多个属性个可以分别调用GetHashCode(),得到一个值乘以一个质数,然后相加。避免溢出加上uncheck.

测试用例代码

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;

namespace AllTests
{
[TestClass]
public class UnitTest1
{
/// <summary>
/// 1. 对于一个值类型,如果其本身存在某个数据可以唯一标明此类型对象,有点儿像数据库中的Key字段,那么用它作为类型的第一个元素
/// 2. 要保证这个类型的对象通过GetHashCode能自始至终一样,就要防止第一个成员被修改,比较好的做法就是给它加上readonly标示
/// 3. 不同版本的.netframework对于值类型的GetHashCode的实现可能实现不同
/// </summary>
[TestMethod]
public void TestStructHash()
{
var t1 = new KeyStruct("AA1", "1");
var t2 = new KeyStruct("AA1", "2");
var t3 = new KeyStruct("AA1", "1");
var t4 = new KeyStruct("BB1", "1");

Debug.WriteLine(t1.GetHashCode());
Debug.WriteLine(t2.GetHashCode());
Debug.WriteLine(t3.GetHashCode());
Debug.WriteLine(t4.GetHashCode());

// 不同的.netframework可能实现不同。有的版本下面test返回True. 当前版本False.
Debug.WriteLine(t1.TestHashCode());
Hashtable ht = new Hashtable();

ht.Add(t1, "v1");
ht.Add(t2, "v2");
// exceptpion
//ht.Add(t3, "test3");

Assert.AreEqual(t1, t2);
}

[TestMethod]
public void TestClassHash1()
{
var t1 = new KeyClass("AA1", "1");
var t2 = new KeyClass("AA1", "2");
var t3 = new KeyClass("AA1", "1");

Debug.WriteLine(t1.GetHashCode());
Debug.WriteLine(t2.GetHashCode());
Debug.WriteLine(t3.GetHashCode());

#region

// 不会先调用GetHashCode函数, 再调用Equals函数判断相等。
// 如果重写了Equals函数,一定要重写GetHashCode函数来达到一致
// 如果实现了IEquatable<ConfigCacheKeyClass>,下面的Equals会调用bool Equals(ConfigCacheKeyClass other)
Debug.WriteLine(t1.Equals(t3));

#endregion

#region Hashtable的Add, Contains会调用GetHashCode函数和   bool Equals(object obj)

Hashtable ht = new Hashtable();

ht.Add(t1, "v1");
ht.Add(t2, "v2");
ht.Add(t3, "v3");

Debug.WriteLine(ht.Contains(t3));

#endregion

#region Dictionary的Add, Contains会调用GetHashCode函数和  bool Equals(ConfigCacheKeyClass other)

IDictionary<KeyClass, string> dic = new Dictionary<KeyClass, string>();

dic.Add(t1, "v1");
dic.Add(t2, "v2");
dic.Add(t3, "v3");

Debug.WriteLine(dic.Keys.Contains(t3));

#endregion

//  Assert.AreEqual(t1, t2);
Assert.AreSame(t1, t3);
}
}

/// <summary>
/// new KeyStruct(), 只要p1相同, 它们的HashCode就一样了
/// </summary>
public struct KeyStruct
{
public readonly string P1;
public readonly string P2;

public KeyStruct(string p1, string p2)
{
this.P1 = (p1 == null ? null : p1.ToLowerInvariant());
this.P2 = (p2 == null ? null : p2.ToLowerInvariant());
}

public bool TestHashCode()
{
return this.GetHashCode() == this.P1.GetHashCode();
}
}

/// <summary>
/// 如果重写了Equals函数,一定要重写GetHashCode函数来达到一致
/// </summary>
public class KeyClass : IEquatable<KeyClass>
{
public readonly string P1;
public readonly string P2;

public KeyClass(string p1, string p2)
{
this.P1 = (p1 == null ? null : p1.ToLowerInvariant());
this.P2 = (p2 == null ? null : p2.ToLowerInvariant());
}

public override bool Equals(object obj)
{
// return this.ServerEnvironmentName == ((ConfigCacheKeyClass)obj).ServerEnvironmentName;
return base.Equals(obj);
}

public override int GetHashCode()
{
return this.P1.GetHashCode();
//return base.GetHashCode();
}

public bool Equals(KeyClass other)
{
return this.P1 == other.P1
&& this.P2 == other.P2;
// throw new NotImplementedException();
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  HashCode