在LINQ中使用Union合并列表时删除重复项

dav*_*avy 10 c# linq

我正在尝试使用list.Unionin 合并两个列表,LinqPad但我无法让它工作,并想检查我的理解是否正确.

鉴于这个简单的类:

public class Test 
{
   public int Id { get; set;}
   public int field1 { get; set; }

   public bool Equals(Test other)
   {        
      return this.Id.Equals(other.Id);
   }
}
Run Code Online (Sandbox Code Playgroud)

两个列表填充如下:

List<Test> list = new List<Test>();
list.Add( new Test { Id = 1, field1 = 1});
list.Add( new Test { Id = 1, field1 = 2});
list.Add( new Test { Id = 2, field1 = 3});
list.Add( new Test { Id = 2, field1 = 4});

List<Test> list2 = new List<Test>();
list2.Add( new Test { Id = 1, field1 = 1});
list2.Add( new Test { Id = 1, field1 = 2});
list2.Add( new Test { Id = 2, field1 = 3});
list2.Add( new Test { Id = 2, field1 = 4});
Run Code Online (Sandbox Code Playgroud)

然后我尝试:var mergedList = list.Union(list2).ToList();使用一个简单的foreach循环输出数据并获得此输出:

ID: 1 -------- 1
ID: 1 -------- 2
ID: 2 -------- 3
ID: 2 -------- 4
ID: 1 -------- 1
ID: 1 -------- 2
ID: 2 -------- 3
ID: 2 -------- 4
Run Code Online (Sandbox Code Playgroud)

我的印象是Union应该删除重复项以返回:

ID: 1 -------- 1
ID: 1 -------- 2
ID: 2 -------- 3
ID: 2 -------- 4
Run Code Online (Sandbox Code Playgroud)

我做错了什么或者我误解了吗?

此外,它是否应该在没有明确覆盖类中的Equals方法的情况下工作Test

谢谢

Ily*_*nov 13

在您的情况下,您只需定义一些LINQ一无所知的方法.这就像创建方法bool HeyEquateMeWith(Test other)和期望一样,LINQ会在执行set操作时调用它.

您需要定义你的类如下(覆盖 ObjectEqualsGetHashCode方法):

public class Test 
{
   public int Id { get; set;}
   public int field1 { get; set; }  

   public override bool Equals(object other) //note parameter is of type object
   {        
        Test t = other as Test;
        return (t != null) ? Id.Equals(t.Id) : false;
   }

   public override int GetHashCode()
   {
        return Id.GetHashCode();
   }
}
Run Code Online (Sandbox Code Playgroud)

现在Union将调用您的重写EqualsGetHashCode方法.您也应该在覆盖方法时始终覆盖.GetHashCodeEquals

  • @davy 默认比较器将查看对象标识(与 `==` 运算符功能相同)。如果将 `Test` 类更改为 `struct`,则默认相等将具有值语义(比较两个结构体的内容,包括 `Id` 和 `field1`) (2认同)