为什么我的 List.Intersect 返回的结果与 Where(List.Contains) 不同的结果

本文关键字:List 结果 Contains Where 返回 我的 为什么 Intersect | 更新日期: 2023-09-27 18:36:52

我正在处理一个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方案中只调用一次。

这是怎么回事?

为什么我的 List.Intersect 返回的结果与 Where(List.Contains) 不同的结果

您需要

正确的GetHashCode()实现才能使用Intersect。不知道为什么,但没有它确实有问题。

没有 GetHashCode() 的小提琴

摆弄 GetHashCode()

似乎GetHashCode的任何实现(即使是不正确的实现)都可以,只是不是默认的对象。

编辑:正如@ScottChamberlain注释中所解释的那样,不是任何不正确的实现都可以工作,它确实需要一个正确的实现(其中每个相等的对象返回一个相等的哈希码)。它不需要高效,只需正确即可。

SequenceEqual要求两个列表具有相同的内容和相同的顺序。问题是顺序不同。改用CollectionAssert.AreEquivalent,它不关心集合的顺序。

CollectionAssert.AreEquivalent(expected,actual);

此外,Intersect确实对结果执行隐式Distinct()。 如果您有两个相同的项目,expected.All(_databaseUsers.Contains)会通过,但两个列表可能具有不同的计数。