Object Equals - whats the basic logic for pure objects or reference types that don't override Equals?

后端 未结 3 621
广开言路
广开言路 2021-02-14 02:03

I got here after reading this and I didn\'t find a relevant answer - So please don\'t mark this as a duplicate until you read the whole question.

I\'ve been using a refl

3条回答
  •  独厮守ぢ
    2021-02-14 02:40

    I think there is some confusion elsewhere on this page. Please notice that there's a difference between numbers 3 and 4!. Another point that is easily mistaken is that the base.Equals instance method (#1) calls RuntimeHelpers.Equals version, and not its own static method Object.ReferenceEquals.

    1. virtual bool ((Object)​this​).Equals(Object)
      [link to source]

      [__DynamicallyInvokable]
      public virtual bool Equals(object obj) => RuntimeHelpers.Equals(this, obj);
      

      This is the instance method in the Object base class. As noted above, this avoids infinite recursion by calling the RuntimeHelpers version which cannot be overridden.

    2. static bool Object.Equals(Object, Object)
      [link to source]

      public static bool Equals(Object objA, Object objB)
      {
         if (objA == objB)
             return true;
      
         if (objA == null || objB == null)
             return false;
      
         return objA.Equals(objB);
      }
      
    3. static bool Object.ReferenceEquals(Object, Object)
      [link to source]

      [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
      [NonVersionable, __DynamicallyInvokable]
      public static bool ReferenceEquals(Object objA, Object objB)
      {
          return objA == objB;
      }
      

      Results in the simplest runtime code. Usually ends up inlined with a trivial CPU comparison of the handle values for the two reference types. Does not call user-defined Equals overrides and makes no attempt to equate non reference-types by any means. That is, no two value types, blittable primitives, enums, etc. will ever equate.

    4. static bool RuntimeHelpers.Equals(Object, Object)
      [link to source]

      [MethodImpl(MethodImplOptions.InternalCall), SecuritySafeCritical]
      public new static extern bool Equals(object o1, object o2);
      

      Notice the extern keyword: there is no IL code; this jumps directly to a CLR-internal code. Also beware that this is a newslot static method, so you must qualify this with "R̲u̲n̲t̲i̲m̲e̲H̲e̲l̲p̲e̲r̲s̲.Equals" at any call site or you'll get the very different behavior of the instance method (#2) Object.Equals.

    5. override bool ((ValueType)​this​).Equals(Object)
      [link to source]

      (Not shown)
      Probably subject to JIT interception anyway. May end up at runtimecallablewrapper.cpp.

    There's much more to discuss here. A major factor is that a lot of the behavior is heavily influenced or intercepted by special JIT processing some of which might depend on whether an instance encountered at runtime can possibly be a value type, or whether the JIT can rule that out. I'm no expert on these matters either, so feel free to comment and/or correct. Let me know if there's interest in more detail on the JIT results, and I might be able to expand this a bit.

提交回复
热议问题