为什么foreach调用GetHashCode?

Bra*_* Ds 1 .net c# linq gethashcode

当我在使用旅行时发现我GetHashCode()的类的覆盖方法Foo被调用时,我感到很惊讶 .但在其他情况下不会发生这种情况.为什么?foreachIEnumerable<Foo>

实际代码的某些部分:

var allVolumeImagesInvolvedInMerge = volumeChainsToMerge
    .SelectMany(x => x);

var allVolumeImagesNotInvolvedInMerge = allVolumeImagesWithinCell
    .Except(allVolumeImagesInvolvedInMerge)
    .Where(vi => volumeImagesNotAllowedToDelete.ContainsFast(vi) == false);

var volumeImagesCandidatesForDeletion = allVolumeImagesNotInvolvedInMerge
    .Where(x => driverVolumeIds.Contains(x.DriverVolumeId));

var groupedVolumeImagesCandidatesForDeletion = volumeImagesCandidatesForDeletion
    .GroupBy(vi => vi.DriverVolumeId);

// here GetHashCode is called
foreach (var group in groupedVolumeImagesCandidatesForDeletion)
{
   ...
}
Run Code Online (Sandbox Code Playgroud)

Tim*_*ter 7

我假设您IEnumerable<Foo>不是类似的集合类型Foo[],List<Foo>而是使用延迟执行的linq查询.因此,当您使用foreach(或ToList,Any等等),你会执行这导致所有被执行参与方法查询.

也许你正在使用GroupBy,Distinct,Intersect,Except,Join或其他使用您的覆盖方法GetHashCodeEquals(如果GetHashCode返回的值相等).

这是一个重现它的简单例子:

public class Foo
{
    public int ID { get; set; }

    public override int GetHashCode()
    {
        return ID.GetHashCode();
    }
    public override bool Equals(object obj)
    {
        Foo f2 = obj as Foo;
        if (f2 == null) return false;
        return ID == f2.ID;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在这个简单的linq查询演示GetHashCodeforeach由于延迟执行Enumerable扩展方法而执行的:

IEnumerable<Foo> list1 = new List<Foo>() { new Foo { ID = 1 }, new Foo { ID = 2 }, new Foo { ID = 3 } };
IEnumerable<Foo> list2 = new List<Foo>() { new Foo { ID = 2 }, new Foo { ID = 3}, new Foo { ID = 4 } };
IEnumerable<Foo> inBoth = list1.Intersect(list2);

// now GetHashCode will be executed (not at list1.Intersect(list2))
foreach (Foo fDup in inBoth)
    Console.WriteLine(fDup.ID);
Run Code Online (Sandbox Code Playgroud)

这是一个演示:http://ideone.com/ekttH3

输出:

before Intersect
after Intersect
in GetHashCode, ID=2
in GetHashCode, ID=3
in GetHashCode, ID=4
in GetHashCode, ID=1
in GetHashCode, ID=2
in Equals, ID=2
in foreach, ID=2
in GetHashCode, ID=3
in Equals, ID=3
in foreach, ID=3
Run Code Online (Sandbox Code Playgroud)