【问题标题】:C# get differences in two matching listsC#获取两个匹配列表的差异
【发布时间】:2016-12-08 04:41:48
【问题描述】:

我需要比较两个列表,其中包含同一类的对象,但不是每个属性都应该用于检查差异。例如。不应使用 Id(主键)属性。

我的示例类:

class MyClass
{
    public System.Nullable<int> Id { get; set; }
    public int VMId { get; set; }
    public string Name { get; set; }
}

var oldR = new List<MyClass>();
oldR.Add(new MyClass() { Id = 1, VMId = 11, Name = "Test1" });
oldR.Add(new MyClass() { Id = 2, VMId = 22, Name = "Test2" });
oldR.Add(new MyClass() { Id = 3, VMId = 33, Name = "Test3" });
oldR.Add(new MyClass() { Id = 4, VMId = 44, Name = "Test4" });
oldR.Add(new MyClass() { Id = 5, VMId = 55, Name = "Test5" });

var newR = new List<MyClass>();
newR.Add(new MyClass() { Id = null, VMId = 22, Name = "Test2" });
newR.Add(new MyClass() { Id = null, VMId = 33, Name = "Test3" });
newR.Add(new MyClass() { Id = null, VMId = 44, Name = "Test43" });
newR.Add(new MyClass() { Id = null, VMId = 55, Name = "Test5" });
newR.Add(new MyClass() { Id = null, VMId = 66, Name = "Test6" });

我想对上述内容做的是匹配 VMId 属性上的两个列表。接下来我想检查一下 Name 属性是否从 oldR 变成了 newR。

基本上我现在想,应该从数据库中删除 Test1,应该添加 Test6,并且应该将 Test4 更新为 Test43。

希望它有意义

编辑: 我应该提一下,我真正的班级有+20个属性。我想现在如何使用 linq 进行比较,而不指定它们?也许只是排除我不想比较的 Id 属性

我怎样才能做到这一点?

【问题讨论】:

标签: c# linq


【解决方案1】:

在 C# 中有一些标准的方法可以做这种事情。

如果您可以控制要比较的类,则可以使其实现IEquatable&lt;T&gt; 接口并重载Object.Equals 方法来定义如何比较实例。您还应该覆盖 Object.GetHashCode 以确保 Dictionarys 和其他哈希集合中的相等性正常工作。

例子:

class MyClass : IEquatable<MyClass> {

    public string name;
    public int primaryKey;

    //IEquatable<T> implementation
    public bool Equals(MyClass other) => 
        !Equals(other, null) 
        && other.name == this.name;

    //Overriding Object methods
    public override bool Equals(object other) =>
        Equals(other as MyClass);

    public override int GetHashCode() => name.GetHashCode();
}

如果您无法控制该类,您可以创建一个实现IEqualityComparer&lt;T&gt; 接口的类,它可以比较另一个类的实例。

例子:

class MyComparer : IEqualityComaprer<MyClass> {
    public bool Equals(MyClass a, MyClass b) {
        if (Object.Equals(a, null)) return Object.Equals(b, null);
        if (Object.Equals(b, null)) return false;
        return a.name == b.name;
    }

    public int GetHashCode(MyClass obj) => obj.name.GetHashCode();
}

许多标准 LINQ 运算符都有接受 IEqualityComparers 作为元素比较的额外参数的重载。

【讨论】:

  • 请选择IEqualityComparer&lt;&gt; 总是,并在您需要的功能处提供所需的比较器。通过覆盖 Equals()GetHashCode(),您可以更改默认行为,当您在不同的上下文中使用该类时,这可能会导致意外行为。
  • @Oliver 提出了一个很好的观点。 IEquatable 是定义该类型的默认比较。不要使用它来满足该类的一个特定用途的需求。 IEqualityComparer 更适合需要特定非标准比较的情况。
【解决方案2】:

请查看这个帖子implement equatable

这很重要,因为它允许您执行 oldR[i].Equals(newR)。只需使用一个嵌套的 foreach 来检查所有对象并输出一个列表,其中列出了哪些项目应该被删除,哪些项目应该被添加(你可以使用 removeList 和 addList 来做到这一点)。如果你走 linq 路线,拥有 iequatable 应该很有用,而且 linq 查询应该更容易编写。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-28
    • 1970-01-01
    • 2018-06-22
    • 1970-01-01
    • 2020-10-30
    • 2019-05-12
    相关资源
    最近更新 更多