首页 > 解决方案 > 在集合之间查找唯一对象

问题描述

我有一个测试,我创建了两个列表。一个代表我已经从某个来源(我无法控制)收集并收集的数据,另一个代表我的存储库中已经存在的已知数据。

它们看起来像这样:

var newAccounts = new[]
{
    new Account
    {
        Id = 1,
        SA_ID = 1,
        SA_Name = "Sa_Name1",
        RelationshipType = "new",
        LE_ID = 1,
        LE_GroupID = 1,
        SiteID = 1,
        MinDate = DateTime.Now.AddDays(-1),
        MaxDate = DateTime.Now.AddDays(1),
        DaysOn = 1,
        Child1 = new List<Child1>{ new Child1
            {
                SiteID = 1,
                MaxDate = DateTime.Today.AddDays(7),
                MinDate = DateTime.Today.AddDays(1),
            }
        },
        Child2 = new List<Child2>
        {
            new Child2
            {
                SA_ID = 1,
                LastUpdate = DateTime.Now.AddDays(-1),
                CommentText = "Account added",
                Status = AccountStatus.AccountAdded.ToString(),
            }
        }
    },
    new Account
    {
        Id = 2,
        SA_ID = 2,
        SA_Name = "Sa_Name2",
        RelationshipType = "new",
        LE_ID = 2,
        LE_GroupID = 2,
        SiteID = 2,
        MinDate = DateTime.Now.AddDays(-2),
        MaxDate = DateTime.Now.AddDays(2),
        DaysOn = 2,
    },
    new Account
    {
        Id = 3,
        SA_ID = 3,
        SA_Name = "Sa_Name3",
        RelationshipType = "new",
        LE_ID = 3,
        LE_GroupID = 3,
        SiteID = 3,
        MinDate = DateTime.Now.AddDays(-3),
        MaxDate = DateTime.Now.AddDays(3),
        DaysOn = 3,
    }
};

var knownAccounts = new[]
{
    new Account
    {
        Id = 1,
        SA_ID = 1,
        SA_Name = "Sa_Name1",
        RelationshipType = "new",
        LE_ID = 1,
        LE_GroupID = 1,
        SiteID = 1,
        MinDate = DateTime.Now.AddDays(-1),
        MaxDate = DateTime.Now.AddDays(1),
        DaysOn = 1,
        Child1 = new List<Child1>{ new Child1
            {
                SiteID = 1,
                MaxDate = DateTime.Today.AddDays(7),
                MinDate = DateTime.Today.AddDays(1),
            }
        },
        Child2 = new List<Child2>
        {
            new Child2
            {
                SA_ID = 1,
                LastUpdate = DateTime.Now.AddDays(-1),
                CommentText = "Account added",
                Status = AccountStatus.AccountAdded.ToString(),
            }
        }
    }
};

在我的单元测试中,我想从中删除Account ID 1newAccounts所以我的收藏中只剩下 2 个条目。到目前为止,这些是我的尝试:

public List<T> ReturnUniqueEntriesList<T>(List<T> newAccounts, List<T> knownAccounts)
{
    var a = knownAccounts.Intersect(newAccounts).ToList();

    var listA = newAccounts.Except(knownAccounts).ToList();
    var listB = knownAccounts.Except(newAccounts).ToList();

    var result = listB.Intersect(listA).ToList();

    return result;
}  

当我运行它时,最终结果为 0。a也返回 0 并且listA&listB简单地返回它们各自的对象。

我在这里做错了什么/错过了什么?任何帮助,将不胜感激

标签: c#listlinqcollections

解决方案


覆盖 Account 的 Equals 和 GetHashcode,以便它们不依赖于默认实现(对象的内存地址)。这意味着 C# 将能够在执行例外时正确地将它们等同起来。

例如:

public class Account{

    public override bool Equals(object other){
      return other is Account a && a.Id == this.Id; //nb; is returns false if other is a null, even if it is an Account
    }

    public override int GetHashCode(){
      return Id.GetHashCode();
    }
}

实际上,以下两个帐户非常不同:

var a = new Account { Id = 1 };
var b = new Account { Id = 1 };

..因为他们住在不同的内存地址。

通过覆盖 Equals 以便它比较另一个的 Id,而不管其他属性,然后您基本上可以实现您似乎描述的“具有相同 ID 的两个帐户对象是等效的”的情况

如果其他属性因素影响到决策,也添加这些属性。Hashcode.Combine 是一种有用的方法,可以将多个哈希码组合起来,以解决获取多个属性的哈希码以产生合适的新信号哈希码的难题 - https://docs.microsoft.com/en-us/dotnet/api/system.hashcode。结合?view=net-5.0


推荐阅读