C# LINQ Except将第一个集合的项发送到IEqualityComparer Equals方法

C# LINQ Except将第一个集合的项发送到IEqualityComparer Equals方法,c#,linq,C#,Linq,我试图实现IEqualityComparer,以便在复杂类型集合之外使用。我在调试时遇到了一个我不知道的奇怪或常见问题。我有两个不同数量的物品收藏,如下所示 {A,B,C,D,E}。除了{A,B},新的CustomComparer.ToList 通过添加ToList,我能够调试覆盖的Equalsx,y。它像预期的那样工作,直到项目B之后的项目C,除了将C和D发送到Equalsx,y,所以我无法区分这些元素属于第一个集合还是其中一个属于第二个集合 下面是我的IEqualityComparer实现。

我试图实现IEqualityComparer,以便在复杂类型集合之外使用。我在调试时遇到了一个我不知道的奇怪或常见问题。我有两个不同数量的物品收藏,如下所示

{A,B,C,D,E}。除了{A,B},新的CustomComparer.ToList

通过添加ToList,我能够调试覆盖的Equalsx,y。它像预期的那样工作,直到项目B之后的项目C,除了将C和D发送到Equalsx,y,所以我无法区分这些元素属于第一个集合还是其中一个属于第二个集合

下面是我的IEqualityComparer实现。DifferenceHighlighter是回调方法,它提供我在调用方位置收集差异

public SubmoduleListComparer(
  Action<FormerGsdmlComparison.SubModuleListDifferenceContainer, string, string> callBack, 
  string firstFileName, 
  string secondFilename)
    {
        DifferenceHighlighter = callBack;
        m_FirstFileName = firstFileName;
        m_SecondFileName = secondFilename;
    }    

public bool Equals(Submodule x, Submodule y)
{
        bool areEqual = true;
        if (x == null || y == null) return false;

        var submoduleDifferences = new FormerGsdmlComparison.SubModuleListDifferenceContainer
        {
            file1 = new FormerGsdmlComparison.Submodule
            {
                orderNumber = x.OrderNumber,
                submoduleId = x.Id,
                submoduleIdentNumber = x.SubmoduleIdentNumber
            }
        };

        if (x.Id != y.Id)
        {
            submoduleDifferences.file2.submoduleId = y.Id;
            areEqual = false;
        }
        if (x.OrderNumber != y.OrderNumber)
        {
            submoduleDifferences.file2.orderNumber = y.OrderNumber;
            areEqual = false;
        }
        if (x.SubmoduleIdentNumber != y.SubmoduleIdentNumber)
        {
            submoduleDifferences.file2.submoduleIdentNumber = y.SubmoduleIdentNumber;
            areEqual = false;
        }

        if (!areEqual)
        {
            DifferenceHighlighter(submoduleDifferences, m_FirstFileName, m_SecondFileName);
        }

        return areEqual;
    }

正如我上面提到的;当第二个集合项的迭代结束时,我期望Except发送null。相反,它将两个元素从第一个集合发送到Equalsx,y是LINQ的默认行为,除了,我应该做更多的检查,还是我遗漏了什么

编辑

第一个集合包含51个元素,第二个集合仅包含7个元素。从两个集合向Equalsx、y发送7个项目后;除非开始从第一个集合发送顺序项。例如:

以上一点正是我所期待的。前两项属于相等法。但在第7次迭代之后

第二个集合没有这些项目。以上项目是第一个系列的第8和第9个元素。所以我的DifferenceHighlighter假设这是两个集合之间的差异

这是预期的行为;除使用仅包含uinque项目的套装而非袋子外;因此,Exception仅返回不同的项:

var demo = new int[] {1, 1} 
  .Except(new int[0])
  .ToList();

Console.Write(string.Join(" ", demo));
结果:

1
在您的情况下,除了测试第1个集合中的项目C和D外,这两个项目都是为了确保只返回不同的项目:

var demo = new int[] {1, 1} 
  .Except(new int[0])
  .ToList();

Console.Write(string.Join(" ", demo));
这是预期的行为;除使用仅包含uinque项目的套装而非袋子外;因此,Exception仅返回不同的项:

var demo = new int[] {1, 1} 
  .Except(new int[0])
  .ToList();

Console.Write(string.Join(" ", demo));
结果:

1
在您的情况下,除了测试第1个集合中的项目C和D外,这两个项目都是为了确保只返回不同的项目:

var demo = new int[] {1, 1} 
  .Except(new int[0])
  .ToList();

Console.Write(string.Join(" ", demo));

原来我完全误解了Except的用途和用法。正如Chris的评论和Dmitry对Except解释的回答,最好使用Zip在两个集合上迭代,检测差异并在另一个集合或其他无数选项中合并结果。除了它真正的意义。经过对邮政编码示例的快速调查,该示例也符合我的条件,如下所示:

foreach (var submoduleListPairs in firstFile.SubmoduleList.Zip(secondFile.SubmoduleList, (x, y) => new { x, y }))
{
    if (submoduleListPairs.x != null && submoduleListPairs.y != null)
    {
        if (submoduleListPairs.x.SubmoduleIdentNumber != submoduleListPairs.y.SubmoduleIdentNumber)
        {
            //Add differences to result collection
        }
        //Do other comparisons like below
    }
    else if (submoduleListPairs.x == null)
    {
        //Notate that second collection contains an item which first one not on result collection
    }
    else if (submoduleListPairs.y == null)
    {
        //Notate that first collection contains an item which second one not on result collection 
    }
}
这可能不是Zip的最佳用法,但我想展示一下它是如何解决我的问题的,以及为什么除了用于比较目的之外,我不应该使用它。我想我有一个想法,即iqualitycomparer和Except是比较问题的关键方法

最后编辑


Zip的想法很鼓舞人心,但如果其中一个集合因其合并集合的目的而缺货,则内置Zipstops。所以我做了另一个更深入的搜索,发现了这个伟大的问题。即使它没有投票权,也大大简化了上述答案。

事实证明,我完全误解了Except的用途和用法。正如Chris的评论和Dmitry对Except解释的回答,最好使用Zip在两个集合上迭代,检测差异并在另一个集合或其他无数选项中合并结果。除了它真正的意义。经过对邮政编码示例的快速调查,该示例也符合我的条件,如下所示:

foreach (var submoduleListPairs in firstFile.SubmoduleList.Zip(secondFile.SubmoduleList, (x, y) => new { x, y }))
{
    if (submoduleListPairs.x != null && submoduleListPairs.y != null)
    {
        if (submoduleListPairs.x.SubmoduleIdentNumber != submoduleListPairs.y.SubmoduleIdentNumber)
        {
            //Add differences to result collection
        }
        //Do other comparisons like below
    }
    else if (submoduleListPairs.x == null)
    {
        //Notate that second collection contains an item which first one not on result collection
    }
    else if (submoduleListPairs.y == null)
    {
        //Notate that first collection contains an item which second one not on result collection 
    }
}
这可能不是Zip的最佳用法,但我想展示一下它是如何解决我的问题的,以及为什么除了用于比较目的之外,我不应该使用它。我想我有一个想法,即iqualitycomparer和Except是比较问题的关键方法

最后编辑


Zip的想法很鼓舞人心,但如果其中一个集合因其合并集合的目的而缺货,则内置Zipstops。所以我做了另一个更深入的搜索,发现了这个伟大的问题。即使它没有UPVOUTS,也大大简化了上述答案。

Except只返回不同的项,例如new int[]{1,1}。Exceptnew int[0]。ToList;will return[1]我本来以为除了发送null外,其他都是空的-我很好奇你为什么会这样想?你在两个集合中都没有空值,那么你为什么期望它将某个东西与空值进行比较呢?@KeremKambur:这样看来,你对除此之外的其他东西的看法是非常错误的。它所做的是返回第一个集合中不在第二个集合中的所有项目。顺序一点也不重要。ie除第2组外,第1组的所有组件。所以{A,B,C,D,E}。除了{A,B}与{E,B,C,D,A}相同,除了{B,A}。实际上,它所做的是在第一个集合中循环并输出值,如果它还没有被输出,如果它不在第二个集合中,正如您在Dmitry的回答中所看到的那样。@Ch
ris感谢您提到了Enumerable.Zip解决方案。它实际上非常符合我的比较条件。很高兴我能够提供帮助。Except只返回不同的项,例如new int[]{1,1}。Exceptnew int[0]。ToList;will return[1]我本来以为除了发送null外,其他都是空的-我很好奇你为什么会这样想?你在两个集合中都没有空值,那么你为什么期望它将某个东西与空值进行比较呢?@KeremKambur:这样看来,你对除此之外的其他东西的看法是非常错误的。它所做的是返回第一个集合中不在第二个集合中的所有项目。顺序一点也不重要。ie除第2组外,第1组的所有组件。所以{A,B,C,D,E}。除了{A,B}与{E,B,C,D,A}相同,除了{B,A}。实际上,它所做的是在第一个集合中循环并输出值,如果它还没有被输出,如果它不在第二个集合中,正如您在Dmitry的回答中所看到的那样。@Chris感谢您提到了Enumerable.Zip解决方案。事实上,这很符合我的比较条件。很高兴我能帮上忙。