I am trying to compare two collections of objects that have the exact same objects in their respective collections. I wrote an extension method for ContainsExactly to do so.
However, I am running into an issue where it is saying the collections are not the same even though they are. Here is the test code below:
public static bool ContainsExactly<T>(this List<T> set1, List<T> set2)
{
if (set1.Count != set2.Count)
return false;
//var isEqual = new HashSet<T>(set1).SetEquals(set2); original test just returned isEqual
var result = set1.Except(set2);
return !result.Any(); //still yields both collections in result
}
So then I have my objects:
public class ReferenceClassObjectTest : IEquatable<ReferenceClassObjectTest>
{
public int Id { get; set; }
public TestObject TestObject { get; set; }
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((ReferenceClassObjectTest)obj);
}
public bool Equals(ReferenceClassObjectTest other)
{
var casted = other as ReferenceClassObjectTest;
if (casted == null)
return false;
return Id == casted.Id && TestObject == casted.TestObject;
}
public override int GetHashCode()
{
var hash = Id;
if(TestObject != null)
{
hash = (hash * 397) ^ TestObject.GetHashCode();
}
else
{
hash = (hash * 397);
}
return hash;
}
}
public class TestObject : IEquatable<TestObject>
{
public int Id { get; set; }
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((TestObject)obj);
}
public bool Equals(TestObject other)
{
var casted = other as TestObject;
if (casted == null)
return false;
return Id == casted.Id;
}
public override int GetHashCode()
{
var hashCode = Id;
hashCode = (hashCode * 397);
return hashCode;
}
}
And when I run my tests, they still return false:
var set2 = new List<ReferenceClassObjectTest>()
{
new ReferenceClassObjectTest
{
Id = 1,
TestObject = new TestObject
{
Id = 2
}
},
new ReferenceClassObjectTest
{
Id = 2,
TestObject = new TestObject
{
Id = 3
}
},
};
var set3 = new List<ReferenceClassObjectTest>()
{
new ReferenceClassObjectTest
{
Id = 1,
TestObject = new TestObject
{
Id = 2
}
},
new ReferenceClassObjectTest
{
Id = 2,
TestObject = new TestObject
{
Id = 3
}
},
};
Assert.IsTrue(set2.ContainsExactly(set3));
Any insights as to why they are not comparing correctly even when overridding GetHashCode()?
I figured the HashSet.SetEquals() would take into account my overrides for GetHashCode() and when I call get hashcode on the two seperate objects in the list, I do get the same hashes:.
set3[1].TestObject.GetHashCode() 1191
set2[1].TestObject.GetHashCode() 1191
set2[0].GetHashCode() 663
set3[0].GetHashCode() 663
Your definition of Equals
for ReferenceClassObjectTest
uses ==
instead of calling Equals
for TestObject
, so you are comparing the reference identity of the TestObject
s.
Change it to be:
return Id == other.Id && TestObject.Equals(other.TestObject);
Alternatively, if you consider TestObject
an immutable object (since it has a public int
field, I am thinking not) you should implement operator==
to call Equals
.