比较对象

我有一个类,它包含一些字符串成员,一些双成员和一些数组对象。

我创建了这个类的两个对象,是否有任何最简单,有效的方法来比较这些对象并说它们相等? 有什么建议?

我知道如何编写比较函数,但这会耗费时间。

你可以真正做到这一点的唯一方法是覆盖bool Object.Equals(object other)以在满足相等条件时返回true,否则返回false。 您还必须重写int Object.GetHashCode()以返回从覆盖Equals()时考虑的所有数据计算的int。

GetHashCode()说一下,请注意GetHashCode()的契约指定当Equals()在比较它们时返回true时,两个对象的返回值必须相等。 这意味着return 0;GetHashCode()的有效实现,但是当类的对象用作字典键或存储在HashSet时,它会导致效率低下。

我实现平等的方式是这样的:

 public class Foo : IEquatable { public bool Equals(Foo other) { if (other == null) return false; if (other == this) return true; // Same object reference. // Compare this to other and return true/false as appropriate. } public override bool Equals(Object other) { return Equals(other as Foo); } public override int GetHashCode() { // Compute and return hash code. } } 

实现GetHashCode()一种简单方法是将您在Equals()考虑相等的所有数据的哈希码进行异或。 因此,例如,如果您为了相等而比较的属性是string FirstName; string LastName; int Id; string FirstName; string LastName; int Id; ,您的实现可能如下所示:

 public override int GetHashCode() { return (FirstName != null ? FirstName.GetHashCode() : 0) ^ (LastName != null ? LastName.GetHashCode() : 0) ^ Id; // Primitives of <= 4 bytes are their own hash codes } 

我通常不会覆盖相等运算符,因为大多数时候我只关心字典键或集合的相等性。 如果你可能通过值而不是引用进行更多的比较,我只会考虑重写相等运算符,因为它在语法上不那么冗长。 但是,您必须记住更改在对象上使用==!=所有位置(包括在Equals()实现中!)以使用Object.ReferenceEquals() ,或将两个操作数转换为object 。 这个讨厌的问题(如果你不小心,可以在你的相等测试中导致无限递归)是我很少覆盖这些运算符的主要原因之一。

在.NET中执行此操作的“正确”方法是为您的类实现IEquatable接口:

 public class SomeClass : IEquatable { public string Name { get; set; } public double Value { get; set; } public int[] NumberList { get; set; } public bool Equals(SomeClass other) { // whatever your custom equality logic is return other.Name == Name && other.Value == Value && other.NumberList == NumberList; } } 

但是,如果你真的想要做得对,那么这不是你应该做的 。 您还应该重写Equals(对象,对象)和GetHashCode(对象)方法,以便无论您的调用代码如何比较相等(可能在字典中或者在某些松散类型的集合中),您的代码而不是引用 – 类型相等将是决定因素:

 public class SomeClass : IEquatable { public string Name { get; set; } public double Value { get; set; } public int[] NumberList { get; set; } ///  /// Explicitly implemented IEquatable method. ///  public bool IEquatable.Equals(SomeClass other) { return other.Name == Name && other.Value == Value && other.NumberList == NumberList; } public override bool Equals(object obj) { var other = obj as SomeClass; if (other == null) return false; return ((IEquatable)(this)).Equals(other); } public override int GetHashCode() { // Determine some consistent way of generating a hash code, such as... return Name.GetHashCode() ^ Value.GetHashCode() ^ NumberList.GetHashCode(); } } 

只花了一整天写一个扩展方法循环,​​通过反映一个对象的属性与各种复杂的逻辑位来处理不同的属性类型,并实际上使它接近良好,然后在16:55,我突然明白,如果你序列化这两个对象,你只需要比较两个字符串……呃

所以这是一个简单的序列化程序扩展方法,甚至适用于字典

  public static class TExtensions { public static string Serialize(this T thisT) { var serializer = new DataContractSerializer(thisT.GetType()); using (var writer = new StringWriter()) using (var stm = new XmlTextWriter(writer)) { serializer.WriteObject(stm, thisT); return writer.ToString(); } } } 

现在你的测试可以很简单

 Asset.AreEqual(objA.Serialise(), objB.Serialise()) 

尚未进行过广泛的测试,但看起来很有前途,更重要的是,简单。 无论哪种方式仍然是一个有用的方法,你的实用程序设置正确吗?

最好的答案是为您的类实现IEquatable – 它可能不是您想要听到的答案,但这是在.NET中实现值等效的最佳方法。

另一个选择是计算类的所有成员的唯一散列,然后对这些散列进行值比较,但这比编写比较函数更有用;)

由于这些是对象,我的猜测是你必须覆盖对象的Equals方法。 否则,只有当两个对象都引用同一个对象时,Equals方法才会使您正常。

我知道这不是你想要的答案。 但由于您class级中的属性很少,您可以轻松覆盖该方法。