从Intersect返回哪个项目,第一个或第二个可枚举的项目是什么?

时间:2018-05-31 08:43:28

标签: c# linq

我有一个项目对象:

class Item : IEquatable<Item>
{
   public string Id { get; }
   public string Name { get; }

    public override bool Equals(object obj)
    {
        return Equals(obj as Item);
    }

    public bool Equals(Item other)
    {
        return other != null && Id == other.Id;
    }

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

做交集:

Item[] items1 = new Item[] { new Item() { Id = 1, Name = 1 } };
Item[] items2 = new Item[] { new Item() { Id = 1, Name = 2 } };

IEnumerable<Item> intersection = items1.Intersect(items2).ToList();

它表明它选择Name = 1项目。

我的问题是保证Intersect始终从第一个可枚举而不是第二个中选择项目?我找不到有关Intersect确切选择的实例的任何信息。

我知道由于两个项目相同,我不需要知道Intersect选择了哪个实例。但这是我的情景:

想象一下这样一种场景,即本地应用程序中存储了项目,并且需要将这些项目与来自后端的项目合并。具有相同ID的在线项目可能会更新Name,但它仍然是#34;相同的项目&#34;与本地存储的项目。这就是了解Intersect选择哪个实例的重要原因。

所以也许我的问题出在其他地方?

.NET允许我们覆盖&#34;平等&#34;两个对象之间的意思。但是,当使用Intersect和其他LINQ时,对我来说似乎有点模糊。

2 个答案:

答案 0 :(得分:2)

您可以查看source code

    public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) {
        if (first == null) throw Error.ArgumentNull("first");
        if (second == null) throw Error.ArgumentNull("second");
        return IntersectIterator<TSource>(first, second, null);
    }

    public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
    {
        if (first == null) throw Error.ArgumentNull("first");
        if (second == null) throw Error.ArgumentNull("second");
        return IntersectIterator<TSource>(first, second, comparer);
    }

    static IEnumerable<TSource> IntersectIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
    {
        Set<TSource> set = new Set<TSource>(comparer);
        foreach (TSource element in second) set.Add(element);
        foreach (TSource element in first)
            if (set.Remove(element)) yield return element;
    }

如您所见,它返回第一组中与第二组中的元素匹配的元素。

然而,正如蒂姆正确地写的那样 - 源代码不是具有约束力的合同。在将来的版本中,此行为可能会发生变化,因此最好不要依赖源代码作为保证。

请注意,Enumerable.Intersect方法Microsoft Docs页面的备注部分也记录了它:

  

两组A和B的交集定义为包含 A 的所有元素的集合,它们也出现在B中,但没有其他元素。

(强调我的)

答案 1 :(得分:2)

Zohar已经回答的问题有点偏离主题。但OP在评论中说:

  

假设我想知道哪些本地商品   与从后端收到的项目相同。我现在的结论是   Intersect无法帮助我解决这个问题。我想知道哪些项目改变了所以我   可以更新本地版本。我不能用它来覆盖本地的   从后端获取的,因为有一些合并逻辑需要   发生,否则我可以覆盖已更改的本地   本地

嗯,这与你在问题中提到的要求不同(合并并从一个来源获取),而Intersect确实没有多大帮助。

var changedNameItems = from l in localItems
                       join o in onlineItems
                       on l.Id equals o.Id
                       where l.Name != o.Name
                       select new{ LocalItem = l, OnlineItem = o };

foreach(var x in changedNameItems)
{
    // if you want to change the local item's name:
    x.LocalItem.Name = x.OnlineItem.Name;
}