使用 Linq 一次更新可观察集合项的两个字段

Posted

技术标签:

【中文标题】使用 Linq 一次更新可观察集合项的两个字段【英文标题】:Updating two fields of an observable collection item at once using Linq 【发布时间】:2018-11-22 03:20:07 【问题描述】:

我有两个相同类型的 Observable Collection 列表:

ObservableCollection<MyDataModel> source;
ObservableCollection<MyDataModel> target;

假设它们已经被填充,所以我尝试从源更新目标,但只有两个字段和第一个匹配的项目(我想保持其余字段不可触及):

foreach (var s in source)

    target.First(t => t.Id == s.Id).Id = s.Id;
    target.First(t => t.Id == s.Id).Desc = s.Desc;

我的模特:

public class MyDataModel

    public int Id  get; set; 
    public string Desc  get; set; 
    public string Country  get; set; 
    public string PostalCode  get; set; 

在上面的 foreach 中,我重复了 target.First 两次,我想避免这种情况并立即执行。是否可以使用 Linq?

【问题讨论】:

为什么你不能直接var current = target.First(t =&gt; t.Id == s.Id); 然后用current 做任何你想做的事? 【参考方案1】:

您可以简单地执行一次First() 并将结果分配给一个变量。

foreach (var s in source)

    var item = target.First(t => t.Id == s.Id);
    item.Id = s.Id;
    item.Desc = s.Desc;

此外,由于您查找项目的条件是 id 是否匹配,因此您实际上并不需要 item.Id = s.Id; 步骤。

编辑

但是,如果在目标中找不到该项目,则上述代码可能会引发异常。这将是一个更好的方法:

foreach (var s in source)

    var item = target.Where(t => t.Id == s.Id).FirstOrDefault();
    if (item != null)
    
        item.Id = s.Id;
        item.Desc = s.Desc;
    

【讨论】:

哦,@Federico 在 cmets 中击败了我。【参考方案2】:

简单回答:

foreach (var s in source)

    var t = target.First(x => x.Id == s.Id);
    t.Desc  = s.Desc;       
    t.Country = s.Country;

简单的答案是 O(source * target) 操作。使用字典可以将性能提高到 O(source + target):

var sourceDict = source.ToDictionary(s => s.Id);
foreach (var t in target)

    MyDataModel s;
    if (sourceDict.TryGetValue(t.Id, out s))
    
        t.Desc = s.Desc;
        t.Country = s.Country;
    

【讨论】:

以上是关于使用 Linq 一次更新可观察集合项的两个字段的主要内容,如果未能解决你的问题,请参考以下文章

可观察的集合没有在 UI 更改时更新

Observable Collection 未更新(可观察的类项集合内的字符串的可观察集合)

LINQ学习——JOIN

可观察的集合未更新

加入集合的 LINQ 更新

Xamarin Forms:如何通知我以前的视图模型而不是需要修改可观察集合?