I designed the following test:
var arrayLength=5000;
object[] objArray=new object[arrayLength];
for(var x=0;x<arrayLength;x++)
{
objArray[x]=new object();
}
objArray[4000]=null;
const int TestSize=int.MaxValue;
System.Diagnostics.Stopwatch v= new Stopwatch();
v.Start();
for(var x=0;x<10000;x++)
{
objArray.Contains(null);
}
v.Stop();
objArray.Contains(null).Dump();
v.Elapsed.ToString().Dump("Contains");
//Any ==
v.Reset();
v.Start();
for(var x=0;x<10000;x++)
{
objArray.Any(o=>o==null);
}
v.Stop();
objArray.Any(x=>x==null).Dump();
v.Elapsed.ToString().Dump("Any");
//Any Equals
v.Reset();
v.Start();
for(var x=0;x<10000;x++)
{
objArray.Any(obj=>object.Equals( obj,null));
}
v.Stop();
objArray.Any(obj=>object.Equals( obj,null)).Dump();
v.Elapsed.ToString().Dump("Any");
The results when null is not present:
Contains False 00:00:00.0606484Any == False 00:00:00.7532898Any object.Equals False 00:00:00.8431783
When null is present at element 4000:
Contains True 00:00:00.0494515Any == True 00:00:00.5929247Any object.Equals True 00:00:00.6700742
When null is present at element 10:
Contains True 00:00:00.0038035Any == True 00:00:00.0025687Any True 00:00:00.0033769
So when the object is near the front, Any is slightly faster; when it’s at the back, it’s much much slower. Why?
Anywill have to call a delegate for every element it checks (an extracallvirtinstruction which is unlikely to get inlined by the JIT).Containsonly performs that check. That’s whyAnyis slower. I suspect the fact thatAnylooks faster than contains when the element is seen very early is that the benchmark can’t reflect it easily since they are very close. The setup time for the method call is the majority of the work done in that case (rather than the actual searching operation).