我有一些包含幾個字段的類。我需要通過值來比較它們,即如果一個類的兩個實例包含相同的數據,則它們是相等的。我已經覆蓋了GetHashCode
和Equals
方法。值等於和循環引用:如何解決無限遞歸?
可能會發生這些類包含循環引用。
例如:我們希望模擬機構(如政府,體育俱樂部等)。一個機構有一個名字。 A Club
是一個有名字和成員名單的機構。每個成員都有一個Person
,它有一個名字和一個最喜歡的機構。如果某個俱樂部的成員將該俱樂部作爲他最喜歡的機構,我們有一個循環參考。
但循環引用與值相等一起導致無限遞歸。下面是一個代碼示例:
interface IInstitution { string Name { get; } }
class Club : IInstitution
{
public string Name { get; set; }
public HashSet<Person> Members { get; set; }
public override int GetHashCode() { return Name.GetHashCode() + Members.Count; }
public override bool Equals(object obj)
{
Club other = obj as Club;
if (other == null)
return false;
return Name.Equals(other.Name) && Members.SetEquals(other.Members);
}
}
class Person
{
public string Name { get; set; }
public IInstitution FavouriteInstitution { get; set; }
public override int GetHashCode() { return Name.GetHashCode(); }
public override bool Equals(object obj)
{
Person other = obj as Person;
if (other == null)
return false;
return Name.Equals(other.Name)
&& FavouriteInstitution.Equals(other.FavouriteInstitution);
}
}
class Program
{
public static void Main()
{
Club c1 = new Club { Name = "myClub", Members = new HashSet<Person>() };
Person p1 = new Person { Name = "Johnny", FavouriteInstitution = c1 }
c1.Members.Add(p1);
Club c2 = new Club { Name = "myClub", Members = new HashSet<Person>() };
Person p2 = new Person { Name = "Johnny", FavouriteInstitution = c2 }
c2.Members.Add(p2);
bool c1_and_c2_equal = c1.Equals(c2); // StackOverflowException!
// c1.Equals(c2) calls Members.SetEquals(other.Members)
// Members.SetEquals(other.Members) calls p1.Equals(p2)
// p1.Equals(p2) calls c1.Equals(c2)
}
}
c1_and_c2_equal
應該返回true
,而事實上我們(人類)可以看出,他們是價值相等的思維一點點,不會導致無限遞歸。但是,我無法真正說出我們如何解釋這一點。但是,既然有可能,我希望有一種方法可以在代碼中解決這個問題!
所以問題是:如何檢查值相等而不會遇到無限遞歸?
請注意,我需要通常解決循環引用,而不僅僅是上面的情況。自c1
參考文獻p1
和p1
參考文獻c1
我將稱它爲2圈。可以有其他的n圈,例如如果一個俱樂部A
有一個會員M
,他的最愛是俱樂部B
,該俱樂部的會員N
最喜歡的俱樂部是A
。那將是一個4圈。其他對象模型也可能允許奇數爲n的n圈。我正在尋找一種解決所有這些問題的方法,因爲我不會提前知道n可以擁有哪些價值。
就像你說的那樣,一個無限遞歸可能發生在X長度的圓圈中(例如:在10次迭代之後,它指向第二個圓柱體,然後圓圈再次開始)。如果遞歸是從1導航到1,而不是1導航到很多,那麼我會包含一個「訪問節點」列表,並驗證當前是否已經處理,如果是,則返回。 – Dryadwoods
正如上面建議的那樣,通過/保存一個哈希集或其他已經被測試/被調用的引用。它可以是一個可選參數,設置爲null,在第一次調用之後被創建並傳遞。 – Rob
在我的opionion中,你的'Equals'實現太嚴格了。爲什麼兩個人只有擁有同一個喜愛的設備纔是平等的?爲什麼一個人在這個週末去新俱樂部時會有所不同?一個簡單的解決方法是引入一個'Id'屬性 –