I assume that your IEnumerable<Foo>
is not a collection type like Foo[]
or List<Foo>
but a linq query which uses deferred execution. So when you use foreach
(or ToList
, Any
etc) you'll execute the query which causes all involved methods to be executed.
Maybe you are using GroupBy
, Distinct
, Intersect
,Except
, Join
or other methods that use your overridden GetHashCode
and Equals
(if GetHashCode
returns an equal value).
Here's a simple example which reproduces it:
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;
}
}
Now this simple linq query demonstrates that GetHashCode
is executed in the foreach
due to the deferred execution of the Enumerable
extension method:
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);
Here's a demo: http://ideone.com/ekttH3
Output:
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