比较两个复杂对象的最佳方法
我有两个复杂的对象,例如 和 。 它们具有大约5个级别的子对象。
我需要最快的方法来说明它们是否相同。
在C#4.0中怎么做?
回答:
在所有自定义类型上实现IEquatable<T>
(通常与覆盖继承Object.Equals
和Object.GetHashCode
方法一起)。对于复合类型,请在包含的类型Equals
内调用包含的类型的方法。对于包含的集合,请使用SequenceEqual
扩展方法,该方法在内部IEquatable<T>.Equals
或Object.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