我正在开发一个Active Directory同步项目,我正在尝试将AD中的用户列表与存储在数据库中的用户列表进行比较。我已经实现了一个自定义UserPrincipal
(我创造性地称之为NetworkUserPrincipal
)来公开我们在入职时需要设置的一些属性。 NetworkUserPrincipal
也实施了IEqualityComparer<NetworkUserPrincipal>
。
我也正在进行小样本的单元测试,我正在尝试制定一个过程来跳过那些信息没有改变的人。这是我的测试:
// a static list of two users
List<NetworkUserPrincipal> expected = JobTestData.InternalActiveDirectoryData.SynchronizedUsers
// returns only one user.
List<NetworkUserPrincipal> actual = _activeDirectoryUsers.Intersect(_databaseUsers).ToList(); // returns only one user.
Assert.IsTrue(expected.All(_databaseUsers.Contains)); // true
Assert.IsTrue(expected.All(_activeDirectoryUsers.Contains)); // true
Assert.IsTrue(expected.SequenceEqual(actual)); // false
但是,如果我将_activeDirectoryUsers.Intersect(_databaseUsers).ToList();
更改为_activeDirectoryUsers.Where(_databaseUsers.Contains).ToList();
,我的最终测试将通过。
当我调试单元测试时,我在我的Equals覆盖函数中放了一个断点,它只在Intersect
场景中被调用一次。
发生了什么事?
答案 0 :(得分:2)
SequenceEqual
要求两个列表具有相同的内容和相同的订单。问题是订单不同。改为使用CollectionAssert.AreEquivalent
,它不关心集合的顺序。
CollectionAssert.AreEquivalent(expected,actual);
此外,Intersect
会对结果执行隐式Distinct()
。如果您有两个相同的项目expected.All(_databaseUsers.Contains)
会通过,但这两个列表可能有不同的计数。
答案 1 :(得分:2)
您需要正确实施GetHashCode()
才能使用Intersect
。不知道为什么,但没有它确实有问题。
似乎 GetHashCode
的任何实现(甚至是不正确的实现)都没有,只是默认的对象之一。
编辑 :正如@ScottChamberlain在评论中解释的那样,没有任何非正确的实现会起作用,它确实需要一个正确的实现(每个相等的对象返回一个相等的哈希码)。它不需要高效,只是正确。