Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C语言中具有双向关联的值相等# 背景_C#_.net_Equals_Iequatable - Fatal编程技术网

C# C语言中具有双向关联的值相等# 背景

C# C语言中具有双向关联的值相等# 背景,c#,.net,equals,iequatable,C#,.net,Equals,Iequatable,在我正在进行的一个C#项目中,我有两个对象,它们之间有双向关联。由于许多原因(例如在集合中使用它们),我需要能够检查值相等(与引用相等),因此我正在实现IEquatable和相关函数 假设 我使用的是C#3.0、.NET3.5和VisualStudio2008(尽管这对于平等性比较例程问题来说并不重要) 约束条件 任何解决方案都必须: 允许双向关联保持不变,同时允许检查值是否相等 允许该类的外部使用从IEquatable调用Equals(Object obj)或Equals(T class

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

假设
  • 我使用的是C#3.0、.NET3.5和VisualStudio2008(尽管这对于平等性比较例程问题来说并不重要)
约束条件 任何解决方案都必须:

  • 允许双向关联保持不变,同时允许检查值是否相等
  • 允许该类的外部使用从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();
        }
    }
}
使用系统;
命名空间EqualityWithBidirectionAlasAssociation
{
公共类人士:IEquatable
{
私有字符串_firstName;
私有字符串_lastName;
私人地址(u地址);;
公众人物(字符串名、字符串名、地址)
{
名字=名字;
LastName=LastName;
地址=地址;
}
公共虚拟地址
{
获取{return\u address;}
设置{u address=value;}
}
公共虚拟字符串名
{
获取{return\u firstName;}
设置{u firstName=value;}
}
公共虚拟字符串LastName
{
获取{return\u lastName;}
设置{u lastName=value;}
}
公共覆盖布尔等于(对象对象对象)
{
//使用“as”而不是强制转换来获取null而不是异常
//如果对象不可转换
Person-Person=obj-as-Person;
返回此。等于(人);
}
公共覆盖int GetHashCode()
{
字符串组合=FirstName+LastName;
返回composite.GetHashCode();
}
#区域可容纳成员
公共虚拟bool等于(其他人)
{
//根据MSDN文档,x.Equals(null)应返回false
if((对象)other==null)
{
返回false;
}
return(this.Address.Equals)(other.Address)
&&this.FirstName.Equals(other.FirstName)
&&this.LastName.Equals(other.LastName));
}
#端区
}
公共类地址:IEquatable
{
私有字符串(街道名称);
私人字符串(城市),;
私有字符串状态;
私人居民;
公共地址(字符串城市、字符串州、字符串街道名称)
{
城市=城市;
状态=状态;
街道名称=街道名称;
_常驻=空;
}
公共虚拟城市
{
获取{return\u city;}
设置{u city=value;}
}
公共虚拟人居民
{
获取{return\u resident;}
设置{u常驻=值;}
}
公共虚拟字符串状态
{
获取{return\u state;}
设置{u state=value;}
}
公共虚拟字符串StreetName
{
获取{return\u streetName;}
设置{u streetName=value;}
}
公共覆盖布尔等于(对象对象对象)
{
//使用“as”而不是强制转换来获取null而不是异常
//如果对象不可转换
地址=obj作为地址;
返回此.Equals(地址);
}
公共覆盖int GetHashCode()
{
字符串组合=街道名称+城市+州;
返回composite.GetHashCode();
}
#区域可容纳成员
公共虚拟布尔等于(地址其他)
{
//根据MSDN文档,x.Equals(null)应返回false
if((对象)other==null)
{
返回false;
}
return(this.City.Equals(other.City)
&&this.State.Equals(其他.State)
&&this.StreetName.Equals(其他.StreetName)
&&这个.Resident.Equals(其他.Resident));
}
#端区
}
公共课程
{
静态void Main(字符串[]参数)
{
地址1=新地址(“西雅图”、“华盛顿”、“威盛街”);
地址2=新地址(“西雅图”、“华盛顿”、“威盛街”);
Person person1=新人(“约翰”,“多伊”,地址1);
地址1.居民=个人1;
地址2.居民=个人1;

如果(AddiSr1.1(AddiSr2))//p>你将类连接得太紧,混合了值和引用。你应该考虑检查一个类的引用相等,或者让它们知道彼此。(通过为特定类提供
internal
专用的
Equals
方法或手动检查其他类的值相等性)。这应该不是什么大问题,因为您的需求明确
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);        // wrong
this.FirstName.Equals(person.FirstName)
this.LastName.Equals(person.LastName)
// and so on
}
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();
        }

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

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

        #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.EqualsIgnoringPerson(other.Address)   // Don't have Address check it's person
                && 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();
        }



        internal virtual bool EqualsIgnoringPerson(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));
        }

        #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.EqualsIgnoringAddress(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)) // <-- No stack overflow!
            {
                Console.WriteLine("The two addresses are equal");
            }

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

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

            Console.Read();
        }
    }
}