为什么foreach调用GetHashCode?

时间:2013-04-03 13:45:19

标签: c# .net 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)
{
   ...
}

1 个答案:

答案 0 :(得分:7)

我假设您的IEnumerable<Foo>不是像Foo[]List<Foo>这样的集合类型,而是使用延迟执行的linq查询。因此,当您使用foreach(或ToListAny等)时,您将执行查询,从而导致执行所有相关方法。

也许您正在使用GroupByDistinctIntersectExceptJoin或其他使用被覆盖的GetHashCode和{的方法{1}}(如果Equals返回相等的值)。

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

GetHashCode

现在,这个简单的linq查询表明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; } } 由于GetHashCode扩展方法的延迟执行而在foreach中执行:

Enumerable

以下是演示http://ideone.com/ekttH3

输出:

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);