将对象集合与 ContainsExactly 进行比较
Comparing Collection of Objects with ContainsExactly
我正在尝试比较在各自集合中具有完全相同对象的两个对象集合。我为 ContainsExactly 编写了一个扩展方法来执行此操作。
但是,我 运行 遇到了一个问题,它说这些集合并不相同,尽管它们是相同的。下面是测试代码:
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
}
那么我有我的对象:
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;
}
}
当我 运行 我的测试时,它们仍然 return 错误:
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));
关于为什么即使在覆盖 GetHashCode() 时它们也不能正确比较的任何见解?
我认为 HashSet.SetEquals() 会考虑我对 GetHashCode() 的覆盖,当我在列表中的两个单独对象上调用 get hashcode 时,我确实得到了相同的哈希:.
set3[1].TestObject.GetHashCode()
1191
set2[1].TestObject.GetHashCode()
1191
set2[0].GetHashCode()
663
set3[0].GetHashCode()
663
您为 ReferenceClassObjectTest
定义的 Equals
使用 ==
而不是为 TestObject
调用 Equals
,因此您正在比较 TestObject
s.
将其更改为:
return Id == other.Id && TestObject.Equals(other.TestObject);
或者,如果您认为 TestObject
是一个不可变对象(因为它有一个 public int
字段,我认为不是),您应该实现 operator==
来调用 Equals
.
我正在尝试比较在各自集合中具有完全相同对象的两个对象集合。我为 ContainsExactly 编写了一个扩展方法来执行此操作。
但是,我 运行 遇到了一个问题,它说这些集合并不相同,尽管它们是相同的。下面是测试代码:
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
}
那么我有我的对象:
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;
}
}
当我 运行 我的测试时,它们仍然 return 错误:
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));
关于为什么即使在覆盖 GetHashCode() 时它们也不能正确比较的任何见解?
我认为 HashSet.SetEquals() 会考虑我对 GetHashCode() 的覆盖,当我在列表中的两个单独对象上调用 get hashcode 时,我确实得到了相同的哈希:.
set3[1].TestObject.GetHashCode() 1191
set2[1].TestObject.GetHashCode() 1191
set2[0].GetHashCode() 663
set3[0].GetHashCode() 663
您为 ReferenceClassObjectTest
定义的 Equals
使用 ==
而不是为 TestObject
调用 Equals
,因此您正在比较 TestObject
s.
将其更改为:
return Id == other.Id && TestObject.Equals(other.TestObject);
或者,如果您认为 TestObject
是一个不可变对象(因为它有一个 public int
字段,我认为不是),您应该实现 operator==
来调用 Equals
.