(This question arises from a discussion that started here)
I was comparing the timings for looking for a true
value in a List
u
Your loop implementation produces the same output as Contains
, but you can't use it in the generic case. I.e. You would have to end up using an Equals
comparison for more complex objects. The Contains
implementation is performing more work than your implementation, so I don't see why you should expect it to be faster in this case.
If you had a list of custom Person
objects say, and overrode the Equals
method to compare, say, their Address
Name
SSNumber
and DateOfBirth
, the loops would perform at nearly identical performance costs.
I would expect for primitive values, then yes a loop iteration is going to outperform the generic Contains
, but this is a premature optimization, you're not going to do (substantially) better than Contains
for more complex object comparisons.
It uses GenericEqualityComparer, if we look at the implementation of the Equals method is looks like this:
public override bool Equals(T x, T y)
{
if ((object) x != null)
{
if ((object) y != null)
return x.Equals(y);
else
return false;
}
else
return (object) y == null;
}
When it checks whether the objects are not equal to null, it makes boxing them and you get two boxing operation. This IL-code shows how it looks:
IL_0002: box !T
IL_0007: ldnull
IL_0008: ceq
Edit by 280Z28: The CIL for the same method is slightly different in .NET 4.5.
public override bool Equals(T x, T y)
{
if (x != null)
return ((y != null) && x.Equals(y));
if (y != null)
return false;
return true;
}
Here is the IL. For anyone looking at Reflector, note that brfalse.s
and brnull.s
are the same instruction.
L_0000: ldarg.1
L_0001: box !T
L_0006: brnull.s L_0021
...
The baseline JIT compiler does not optimize away the box operation, but I have not checked with NGen or the optimizing compiler to see if they do.