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
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
.
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 theRuntimeHelpers
version which cannot be overridden.
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); }
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.
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 anewslot
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
.
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.