比较两个复杂对象的最佳方法

我有两个复杂的对象,例如 和 。 它们具有大约5个级别的子对象。

我需要最快的方法来说明它们是否相同。

在C#4.0中怎么做?

回答:

在所有自定义类型上实现IEquatable<T>(通常与覆盖继承Object.EqualsObject.GetHashCode方法一起)。对于复合类型,请在包含的类型Equals内调用包含的类型的方法。对于包含的集合,请使用SequenceEqual扩展方法,该方法在内部IEquatable<T>.EqualsObject.Equals在每个元素上调用。显然,这种方法将需要您扩展类型的定义,但其结果比任何涉及序列化的通用解决方案都快。

:这是三个层次的嵌套的人为的示例。

对于值类型,通常可以只调用它们的Equals方法。即使从未显式分配字段或属性,它们仍将具有默认值。

对于引用类型,应首先调用ReferenceEquals,以检查引用是否相等–当您碰巧引用同一对象时,这可以提高效率。它还将处理两个引用均为空的情况。如果该检查失败,请确认您实例的字段或属性不为null(以避免NullReferenceException),然后调用其Equals方法。由于我们的成员类型正确,因此IEquatable<T>.Equals将直接调用该方法,而绕过重写的Object.Equals方法(由于强制类型转换,其执行速度会稍慢)。

覆盖时Object.Equals,还应该覆盖Object.GetHashCode; 为了简洁起见,我在下面没有这样做。

public class Person : IEquatable<Person>

{

public int Age { get; set; }

public string FirstName { get; set; }

public Address Address { get; set; }

public override bool Equals(object obj)

{

return this.Equals(obj as Person);

}

public bool Equals(Person other)

{

if (other == null)

return false;

return this.Age.Equals(other.Age) &&

(

object.ReferenceEquals(this.FirstName, other.FirstName) ||

this.FirstName != null &&

this.FirstName.Equals(other.FirstName)

) &&

(

object.ReferenceEquals(this.Address, other.Address) ||

this.Address != null &&

this.Address.Equals(other.Address)

);

}

}

public class Address : IEquatable<Address>

{

public int HouseNo { get; set; }

public string Street { get; set; }

public City City { get; set; }

public override bool Equals(object obj)

{

return this.Equals(obj as Address);

}

public bool Equals(Address other)

{

if (other == null)

return false;

return this.HouseNo.Equals(other.HouseNo) &&

(

object.ReferenceEquals(this.Street, other.Street) ||

this.Street != null &&

this.Street.Equals(other.Street)

) &&

(

object.ReferenceEquals(this.City, other.City) ||

this.City != null &&

this.City.Equals(other.City)

);

}

}

public class City : IEquatable<City>

{

public string Name { get; set; }

public override bool Equals(object obj)

{

return this.Equals(obj as City);

}

public bool Equals(City other)

{

if (other == null)

return false;

return

object.ReferenceEquals(this.Name, other.Name) ||

this.Name != null &&

this.Name.Equals(other.Name);

}

}

:这个答案是几年前写的。从那时起,我开始不再IEquality<T>为此类情况实现可变类型的实现了。平等有两个概念:

和对 。在内存表示级别上,通常将它们区分为“引用相等”和“值相等”(请参阅​​“

相等比较”)。但是,相同的区别也可以应用于域级别。假设您的Person班级拥有一个PersonId属性,该属性对于每个实际的人都是唯一的。具有相同PersonId但不同Age值的两个对象是否应视为相等或不同?上面的答案假设一个在等价之后。但是,IEquality<T>接口(例如集合),它们假定此类实现提供了

identity

。例如,如果要填充HashSet<T>,通常会期望TryGetValue(T,T)调用返回仅共享参数标识的现有元素,而不必返回内容完全相同的等效元素。该概念由以下注释强制执行GetHashCode

通常,对于可变引用类型,GetHashCode()仅在以下情况下才应覆盖:

  • 您可以从不可变的字段中计算哈希码;要么
  • 您可以确保在对象包含在依赖于其哈希代码的集合中时,该可变对象的哈希代码不会更改。

以上是 比较两个复杂对象的最佳方法 的全部内容, 来源链接: utcz.com/qa/413637.html

回到顶部