C# 为什么foreach调用GetHashCode?
当我使用foreach在IEnumerable中旅行时,发现调用了Foo类的override GetHashCode方法时,我感到很惊讶。但在其他情况下不会发生这种情况。为什么? 真实代码的某些部分:C# 为什么foreach调用GetHashCode?,c#,.net,linq,gethashcode,C#,.net,Linq,Gethashcode,当我使用foreach在IEnumerable中旅行时,发现调用了Foo类的override GetHashCode方法时,我感到很惊讶。但在其他情况下不会发生这种情况。为什么? 真实代码的某些部分: var allVolumeImagesInvolvedInMerge = volumeChainsToMerge .SelectMany(x => x); var allVolumeImagesNotInvolvedInMerge = allVolumeImagesWithinCe
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)
{
...
}
我假设IEnumerable不是Foo[]或List这样的集合类型,而是使用延迟执行的linq查询。因此,当您使用foreach或ToList时,任何etc都将执行导致执行所有相关方法的查询
如果GetHashCode返回一个相等的值,那么您可能正在使用GroupBy、Distinct、Intersect、Except、Join或其他使用覆盖的GetHashCode和equals的方法
下面是一个简单的例子,它再现了这一点:
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;
}
}
现在,这个简单的linq查询演示了由于可枚举扩展方法的延迟执行,GetHashCode在foreach中执行:
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);
我假设IEnumerable不是Foo[]或List这样的集合类型,而是使用延迟执行的linq查询。因此,当您使用foreach或ToList时,任何etc都将执行导致执行所有相关方法的查询
如果GetHashCode返回一个相等的值,那么您可能正在使用GroupBy、Distinct、Intersect、Except、Join或其他使用覆盖的GetHashCode和equals的方法
下面是一个简单的例子,它再现了这一点:
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;
}
}
现在,这个简单的linq查询演示了由于可枚举扩展方法的延迟执行,GetHashCode在foreach中执行:
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);
发布您的循环和类在GetHashCode上放置一个断点,然后查看调用堆栈。我打赌IEnumerable涉及到我在reflector中看到的猜测是,IEnumerable正在抽象一个集合,因为它本身只是一个使用哈希代码的接口,可能用于MoveNext。如果显示示例代码,也许你可以得到一个更具体的答案。@EricLippert:或者他的IEnumerable正在包装一个字典或哈希表。发布你的循环,你的类在GetHashCode上放置一个断点,然后查看调用堆栈。我打赌IEnumerable涉及到我在reflector中的猜测,即IEnumerable正在抽象一个集合,因为它本身是只是一个使用散列代码的接口,可能用于MoveNext。如果您展示示例代码,也许您可以得到更具体的答案。@EricLippert:或者他的IEnumerable正在包装字典或哈希表。