gpt4 book ai didi

c# - C# 中双向关联的值相等

转载 作者:行者123 更新时间:2023-11-30 12:54:04 27 4
gpt4 key购买 nike

背景

在我正在处理的 C# 项目中,我有两个对象,它们之间存在双向关联。出于多种原因(例如,在集合中使用它们),我需要能够检查值是否相等(与引用相等),因此我正在实现 IEquatable 和相关函数。

假设

  • 我使用的是 C# 3.0、.NET 3.5 和 Visual Studio 2008(尽管相等比较例程问题应该无关紧要)。

约束

任何解决方案都必须:

  • 允许双向关联保持不变,同时允许检查值是否相等。
  • 允许类的外部使用从 IEquatable 调用 Equals(Object obj) 或 Equals(T class) 并接收正确的行为(例如在 System.Collections.Generic 中)。

问题

当实现 IEquatable 以检查具有双向关联的类型的值相等性时,会发生无限递归,从而导致堆栈溢出。

注意:类似地,在 GetHashCode 计算中使用类的所有字段将导致类似的无限递归并导致堆栈溢出问题。


问题

如何在不导致堆栈溢出的情况下检查具有双向关联的两个对象之间的值是否相等?


代码

注意:这段代码只是为了显示问题,而不是演示我正在使用的遇到此问题的实际类设计

using System;

namespace EqualityWithBiDirectionalAssociation
{

public class Person : IEquatable<Person>
{
private string _firstName;
private string _lastName;
private Address _address;

public Person(string firstName, string lastName, Address address)
{
FirstName = firstName;
LastName = lastName;
Address = address;
}

public virtual Address Address
{
get { return _address; }
set { _address = value; }
}

public virtual string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}

public virtual string LastName
{
get { return _lastName; }
set { _lastName = value; }
}

public override bool Equals(object obj)
{
// Use 'as' rather than a cast to get a null rather an exception
// if the object isn't convertible
Person person = obj as Person;
return this.Equals(person);
}

public override int GetHashCode()
{
string composite = FirstName + LastName;
return composite.GetHashCode();
}


#region IEquatable<Person> Members

public virtual bool Equals(Person other)
{
// Per MSDN documentation, x.Equals(null) should return false
if ((object)other == null)
{
return false;
}

return (this.Address.Equals(other.Address)
&& this.FirstName.Equals(other.FirstName)
&& this.LastName.Equals(other.LastName));
}

#endregion

}

public class Address : IEquatable<Address>
{
private string _streetName;
private string _city;
private string _state;
private Person _resident;

public Address(string city, string state, string streetName)
{
City = city;
State = state;
StreetName = streetName;
_resident = null;
}

public virtual string City
{
get { return _city; }
set { _city = value; }
}

public virtual Person Resident
{
get { return _resident; }
set { _resident = value; }
}

public virtual string State
{
get { return _state; }
set { _state = value; }
}

public virtual string StreetName
{
get { return _streetName; }
set { _streetName = value; }
}

public override bool Equals(object obj)
{
// Use 'as' rather than a cast to get a null rather an exception
// if the object isn't convertible
Address address = obj as Address;
return this.Equals(address);
}

public override int GetHashCode()
{
string composite = StreetName + City + State;
return composite.GetHashCode();
}


#region IEquatable<Address> Members

public virtual bool Equals(Address other)
{
// Per MSDN documentation, x.Equals(null) should return false
if ((object)other == null)
{
return false;
}

return (this.City.Equals(other.City)
&& this.State.Equals(other.State)
&& this.StreetName.Equals(other.StreetName)
&& this.Resident.Equals(other.Resident));
}

#endregion
}

public class Program
{
static void Main(string[] args)
{
Address address1 = new Address("seattle", "washington", "Awesome St");
Address address2 = new Address("seattle", "washington", "Awesome St");

Person person1 = new Person("John", "Doe", address1);

address1.Resident = person1;
address2.Resident = person1;

if (address1.Equals(address2)) // <-- Generates a stack overflow!
{
Console.WriteLine("The two addresses are equal");
}

Person person2 = new Person("John", "Doe", address2);
address2.Resident = person2;

if (address1.Equals(address2)) // <-- Generates a stack overflow!
{
Console.WriteLine("The two addresses are equal");
}

Console.Read();
}
}
}

最佳答案

您将类耦合得太紧密并且混合了值和引用。您应该考虑检查其中一个类的引用相等性或让它们相互了解(通过为特定类提供 internal 专门的 Equals 方法或手动检查值相等性另一类)。这应该没什么大不了的,因为您的要求明确要求这种耦合,所以您不会通过这样做引入耦合。

关于c# - C# 中双向关联的值相等,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/731206/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com