C# 使用Linq在集合之间添加、更新、删除

C# 使用Linq在集合之间添加、更新、删除,c#,wpf,linq,C#,Wpf,Linq,这是我的设想。我使用WPF并使用双向绑定每60秒显示一次从服务调用接收的集合对象。在第一次调用中,我创建了一个对象集合,该集合将从服务对象集合中显示。在后续调用中,我需要将服务集合与现有集合进行比较,然后执行以下三项操作之一: 如果两个集合中都存在该项,则使用服务集合中对象的值更新显示集合中对象的所有值 如果该项存在于服务集合而不是显示集合中,则将其添加到显示集合中 如果该项存在于显示集合而不是服务集合中,则将其从显示集合中删除 我正在寻找最好的方法来做到这一点 添加和删除 在这里做一个左连接,

这是我的设想。我使用WPF并使用双向绑定每60秒显示一次从服务调用接收的集合对象。在第一次调用中,我创建了一个对象集合,该集合将从服务对象集合中显示。在后续调用中,我需要将服务集合与现有集合进行比较,然后执行以下三项操作之一:

  • 如果两个集合中都存在该项,则使用服务集合中对象的值更新显示集合中对象的所有值
  • 如果该项存在于服务集合而不是显示集合中,则将其添加到显示集合中
  • 如果该项存在于显示集合而不是服务集合中,则将其从显示集合中删除
  • 我正在寻找最好的方法来做到这一点

    添加和删除 在这里做一个左连接,并返回另一侧的所有本质上唯一的东西,然后根据需要添加或删除,这是否更明智

    既然Linq应该合并两者并忽略重复项,那么我是否应该尝试进行联合呢?
    如果是,它如何决定独特性?它评估了所有的属性吗?我是否可以指定合并时保留哪个集合以及放弃哪个集合

    我应该使用Except来创建差异列表并以某种方式使用它吗

    我是否应该使用Where/Not In logic创建一个新的列表来添加和删除

    更新 既然集合不是字典,那么进行比较的最佳方法是什么:

    list1.ForEach(x => list2[x.Id].SomeProperty = x.SomeProperty);
    
    除了像上面那样指定每个属性值之外,是否有其他复制所有属性值的方法?我是否可以在Linq中执行某种浅层复制,而不替换存在的实际对象


    我不想每次都清除列表并重新添加所有内容,因为对象绑定在显示中,并且我在属性中具有跟踪值更改时的偏差的逻辑。

    您可以使用except和intersect方法来完成大部分要做的事情

    但是,根据对象的大小,这可能会占用大量资源

    我建议如下

    var listIDsA = collectionA.Select(s => s.Id).Distinct().ToList();
    
    var listIDsB = collecitonB.Select(s => s.Id).Distinct().ToList();
    
    var idsToRemove  = listIDsB.Select (s => !listIDsA.Contains(s.Id)).ToList();
    
    var idsToUpdate = listIDsB.Select(s => listIDsA.Contains(s.Id)).ToList();
    
    var idsToAdd = listIDsA.SelecT(s => !listIDsB.Contains(s.Id)).ToList();
    
    然后使用这三个新集合,您可以添加/删除/更新相应的记录

    为了获得更好的性能,还可以使用hashedset而不是IEnumerables。这将需要您创建一个扩展类来添加该功能。这里有一个很好的解释如何做到这一点(并不复杂)


    如果执行此操作,则需要将前两行中的.ToList()替换为.ToHasedSet()

    为了进行比较,需要覆盖equals并获取hashcode

    然后您可以使用List.Contains

    如果您可以使用HashSet,那么您将获得更好的性能

    未测试的代码

    ListDisplay.Remove(x => !ListSerice.Contains(x));
    Foreash(ListItem li in ListDisplay)
    {
       ListItem lis =  ListSerice.FirstOrDefault(x => x.Equals(li));
       if (lis == null) continue;
       // perform update
    }
    Foreach(ListItem li in ListSerice.Where(x => !ListDisplay.Contains(x))) ListDisplay.Add(li);
    

    您所谓的比较示例是一个赋值,而不是一个比较。你的意思是写“分配”吗?在网络中,你正在用服务替换显示器。为什么不清空显示并用服务填充它呢?您是否通过添加对象,例如,
    list1.add(list2[index])?如果是,则无需更新属性值;对象是相同的。同一对象是两个列表中的一个元素。如果另一个列表在后续调用后包含新的不相同对象,那么您只需设置
    list1[targetIndex]=list2[sourceIndex]
    (当然,在确定适当的目标索引之后)。@phoog我的道歉我只是想表明,如果它是字典,我可以使用[key]确定要更新的对象。@phoog在本例中,我不认为我可以使用列表索引更改指针,原因有二。该列表中的项双向绑定到WPF中的网格。这样做只是交换引用,而不是更新实际数据。我需要更改属性,因为存在跟踪偏差的逻辑。如果要执行大量的
    包含
    检查,我建议使用
    hashSetIdsA
    B
    而不是
    列表idsa
    B
    。@Rawling谢谢。我用这些信息更新了我的回复。带有.Contains的每一行都给出了错误,“Unknown method”Select(?)“of”System.Collections.Generic.List.When执行更新是几乎将每个属性设置为1乘1的唯一方法?是否有任何类型的浅层副本可以在不替换对象的情况下进行更新?只需搜索浅层副本。来吧,显示一些努力。抱歉,我不仅仅是想放松。我的问题只是遇到了错误。浅层Copy或MemberwiseClone通过创建对象的新实例来工作。它实际上不会将这些值转置到另一个现有对象上。我想知道linq中是否存在这样一种能力,即不单独指定对象上的所有属性,也不替换要更新的对象。我怀疑答案是s没有,但我以前很惊讶。我知道不是在LINQ中。我只需要手动执行。这比枚举属性和一些不需要复制的属性(例如ID)更有效。