c#如何判断两个物体是否相等

c#如何判断两个物体是否相等,c#,comparison,hash,C#,Comparison,Hash,我想知道比较两个物体并找出它们是否相等的最佳方法。我正在重写GethashCode和Equals。因此,基本类如下所示: public class Test { public int Value { get; set; } public string String1 { get; set; } public string String2 { get; set; } public override int GetHashCode() { r

我想知道比较两个物体并找出它们是否相等的最佳方法。我正在重写GethashCode和Equals。因此,基本类如下所示:

public class Test
{
    public int Value { get; set; }
    public string String1 { get; set; }
    public string String2 { get; set; }

    public override int GetHashCode()
    {
        return Value ^ String1.GetHashCode() ^ String2.GetHashCode();
    }

    public override bool Equals( object obj )
    {
        return GetHashCode() == obj.GetHashCode();
    }
}
出于测试目的,我创建了两个对象:

Test t = new Test()
{
    Value = 1,
    String1 ="One",
    String2 = "One"
};

Test t2 = new Test()
{
    Value = 1,
    String1 = "Two",
    String2 = "Two"
};

bool areEqual = t.Equals( t2 );
在测试中,areEqual返回true事件,尽管两个对象不同。我意识到这是因为String1和String2在每个对象中都是相同的值,因此在散列时相互抵消


是否有更好的方法来解决我的问题,即散列对象?

您当前的相等方法已被破坏-值多于可能的散列代码。您偶尔会有不相等的值,但给出相同的散列,这是完全合理的(也是预期的)。Equals应检查实际值:

需要注意的几点:

  • 如果
    String1
    String2
    相同,则生成hashcode的方法将为任何固定的
    值提供相同的值;如果
    String1
    String2
    为空,它也会爆炸。这是使用XOR进行散列的一个不幸方面。我喜欢这样的东西:

    // Put this extension method in a utility class somewhere
    public static int SafeGetHashCode<T>(this T value) where T : class
    {
        return value == null ? 0 : value.GetHashCode();
    }
    
    // and this in your actual class
    public override int GetHashCode()
    {
        int hash = 19;
        hash = hash * 31 + Value;
        hash = hash * 31 + String1.SafeGetHashCode();
        hash = hash * 31 + String2.SafeGetHashCode();
        return hash;
    }
    
    //将此扩展方法放在某个实用程序类中
    公共静态int-SafeGetHashCode(此T值),其中T:class
    {
    返回值==null?0:value.GetHashCode();
    }
    //这是在你的课堂上
    公共覆盖int GetHashCode()
    {
    int hash=19;
    散列=散列*31+值;
    hash=hash*31+String1.SafeGetHashCode();
    hash=hash*31+String2.SafeGetHashCode();
    返回散列;
    }
    
  • 一般来说,当涉及到继承时,平等就变得棘手了。你可能想考虑密封你的类。

  • 您可能还希望实现
    IEquatable


您的
Equals
是不正确的-这应该定义两个事物相等的含义-并且具有相同的哈希代码并不意味着相等(但是,不同的哈希代码意味着不相等)。如果“相等”表示“两个字符串成对相等”,则测试该值

你是一个更好的散列;xor在这方面是臭名昭著的,因为通过xor本身获得一个值是微不足道的。更好的方法可能是:

int i = 0x65407627;
i = (i * -1521134295) + Value.GetHashCode();
i = (i * -1521134295) + (String1 == null ? 0 : String1.GetHashCode());
i = (i * -1521134295) + (String2 == null ? 0 : String2.GetHashCode());
return i;
public override bool Equals(object obj)
{
    Test other = obj as Test;
    if (other == null)
        return false;

    return (Value == other.Value)
        && (String1 == other.String1)
        && (String2 == other.String2);
}

对于任意两个对象,对象相等意味着哈希代码相等,但哈希代码相等并不意味着对象相等。从MSDN开始:

哈希函数必须具有 以下特性:

如果两个对象比较相等,则 每个对象的GetHashCode方法 必须返回相同的值。然而, 如果两个对象不进行比较 equal,用于 两个对象不必返回 不同的价值观

换句话说,您的
等于
写错了。应该是这样的:

int i = 0x65407627;
i = (i * -1521134295) + Value.GetHashCode();
i = (i * -1521134295) + (String1 == null ? 0 : String1.GetHashCode());
i = (i * -1521134295) + (String2 == null ? 0 : String2.GetHashCode());
return i;
public override bool Equals(object obj)
{
    Test other = obj as Test;
    if (other == null)
        return false;

    return (Value == other.Value)
        && (String1 == other.String1)
        && (String2 == other.String2);
}

GetHashCode
有助于集合(如
Dictionary
)快速确定近似相等
Equals
用于比较两个对象是否真的是相同的。

函数Equals不是总是针对同一类型进行测试吗

//override
    public bool Equals(Test other)//(object obj) 
    {
        //return GetHashCode() == obj.GetHashCode();
        return (Value == other.Value) &&
               (String1 == other.String1) &&
               (String2 == other.String2);
    }
问候 Oops

简单

Object.Equals(obj1, obj2);

您可以将这两个对象序列化为JSON,然后比较这两个字符串,看看它们是否相同

比如说

JavaSriptSerializer serialiser = new JavaScriptSerializer();

string t1String = serialiser.Serialize(t);
string t2String = serialiser.Serialize(t2);

if(t1String == t2String)
   return true; //they are equal
else
   return false;

(更新,借用了C#编译器用于匿名类型的种子和乘法器)你为什么选择这些值来生成哈希代码?@Carlos:参见Marc之前的评论:)@Jon:我以前见过,但我不明白。谢谢你的帮助。@Carlos-我真的不知道MS为什么特别选择这些方法-不过种子+因子方法已经足够普遍了。这些值几乎可以是任何可以提供适当分散的值(并且-ve可能有帮助)Re
SafeGetHashCode
-只是要提到
EqualityComparer.GetHashCode
将做一些非常类似的事情-尽管扩展方法非常整洁;pYour的答案非常好,而第一个词是错误的:“No”是对他的问题的错误回答:“有更好的方法吗……”此外,Simons测试类没有基类,也没有实现接口。所以override关键字实际上是wrong@Oops:将修复“否”。。。但是测试类确实有一个基类——System.Object的隐式基类。这些方法正在重写对象实现。您应该重写对象中的方法。您还可以实现
IEquatable
,这是您指定此签名的时候。不知道,这是VS2010测试版的问题吗?如果我在这里使用override,VS会说:“Test.Equals(Test)”:找不到合适的方法来重写这一切都取决于obj1/obj2是否为引用类型。看,这实际上是最好的答案,它是最简单、最清晰和100%正确的。它并不总是有效的。JSON有其自身的局限性。依靠JSON来比较一般对象不是一个好主意。尝试了这个方法后,它就不起作用了。由于JSON中属性的顺序不同,它会导致误报。