比较在Dictionary中用作Key的对象

Sai*_*int 17 c# comparison dictionary contains equals

我的课:

public class myClass
{
    public int A { get; set; }
    public int B { get; set; }
    public int C { get; set; }
    public int D { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

和主要的例子:

Dictionary<myClass, List<string>> dict = new Dictionary<myClass, List<string>>();
myClass first = new myClass();
first.A = 2;
first.B = 3;

myClass second = new myClass();
second.A = 2;
second.B = 3;
second.C = 5;
second.D = 6;

dict.Add(first, new List<string>());

if (dict.ContainsKey(second))
{
    //
    //should come here and update List<string> for first (and only in this example) key 
    //
}
else
{
    //
    //if myFirst object has difference vlues of A or B properties
    //
    dict.Add(second, new List<string>());
}
Run Code Online (Sandbox Code Playgroud)

这该怎么做?

Sco*_*ain 30

如果您始终只希望字典在A和B上进行比较,则有两种选择.无论是使用构造实现IEqualityComparer<TKey>,把你的比较逻辑有,或有你的类实现的GetHashCode和equals所以默认的比较会给你你正在寻找的结果.IEquateable<T>

如果您只想在一种情况下比较A和B,则需要使用.Keys属性和Linq扩展方法包含允许您传入的IEqualityComparer<T>.但是,当这样做时,你会失去使用Dictionary的速度优势,所以请谨慎使用它.

public class MyClassSpecialComparer : IEqualityComparer<myClass>
{
    public bool Equals (myClass x, myClass y)
    { 
        return x.A == y.A && x.B == y.B 
    }

    public int GetHashCode(myClass x)
    {
       return x.A.GetHashCode() + x.B.GetHashCode();
    }


}


 //Special case for when you only want it to compare this one time
 //NOTE: This will be much slower than a normal lookup.
    var myClassSpecialComparer = new MyClassSpecialComparer();
    Dictionary<myClass, List<string>> dict = new Dictionary<myClass, List<string>>();
    //(Snip)
    if (dict.Keys.Contains(second, myClassSpecialComparer ))
    {
        //
        //should come here and update List<string> for first (and only in this example) key 
        //
    }

 //If you want it to always compare
    Dictionary<myClass, List<string>> dict = new Dictionary<myClass, List<string>>(new MyClassSpecialComparer());
Run Code Online (Sandbox Code Playgroud)


Pet*_*hie 8

默认情况下,比较会根据哈希代码将对象放入存储区.Equals如果两个哈希码相同,则执行详细比较(通过调用).如果您的类既不提供GetHashCode也不实现相等,object.GetHashCode则将使用默认值- 在这种情况下,您的类的任何特定内容都不会用于值比较语义.只会找到相同的参考.如果您不想这样做,请实现GetHashCode并实现相等.

例如:

public class myClass
{
    public int A { get; set; }
    public int B { get; set; }
    public int C { get; set; }
    public int D { get; set; }

    public bool Equals(myClass other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return other.A == A && other.B == B && other.C == C && other.D == D;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != typeof (myClass)) return false;
        return Equals((myClass) obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int result = A;
            result = (result*397) ^ B;
            result = (result*397) ^ C;
            result = (result*397) ^ D;
            return result;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @AlexanderEfimov这使得代码依赖于顺序如果你只是对所有项进行异或运行`A = 1,B = 2`会生成相同的散列`3`有'A = 2,B = 1`.但是如果你将第二项乘以397,它会给你'A = 1,B = 2'产生`795`,但是'A = 2,B = 1`产生`399`.这为您提供了更好的哈希分布(一个注释,您应该不添加xor并使用另一个素数初始化第一个数字) (2认同)
  • 有关更多说明,请参阅[此SO问题和答案](http://stackoverflow.com/questions/892618/create-a-hashcode-of-two-numbers). (2认同)