Loop implementation of List.Contains() appears faster than the built-in one. Is it? If so, why?

后端 未结 2 1952
星月不相逢
星月不相逢 2021-01-11 12:01

(This question arises from a discussion that started here)

I was comparing the timings for looking for a true value in a List u

相关标签:
2条回答
  • 2021-01-11 12:49

    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.

    0 讨论(0)
  • 2021-01-11 13:02

    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.

    0 讨论(0)
提交回复
热议问题