Mostafa Mahdieh
Mostafa Mahdieh

Reputation: 986

What is the default behavior of Equals Method?

Let A be a class with some members as x, y, z:

Class A {
  int x;
  int y;
  String z;
  ...
}

A is an Object so it inherits the "Equals" functions defined in Object. What is the default behavior of this function? Does it check for the equality of members or does it check for reference equality?

Upvotes: 51

Views: 31247

Answers (3)

user1121956
user1121956

Reputation: 1961

For "I want to know exactly how it works" kind of people below is the source code reference. I'm not sure though how the "loader trick" described in the comment in the first code fragment relates to the fact that in C++ code there is also handling for a ValueType in the same method.

https://source.dot.net/#System.Private.CoreLib/Object.cs,50

// Returns a boolean indicating if the passed in object obj is
// Equal to this.  Equality is defined as object equality for reference
// types and bitwise equality for value types using a loader trick to
// replace Equals with EqualsValue for value types).
public virtual bool Equals(object? obj)
{
    return RuntimeHelpers.Equals(this, obj);
}

https://source.dot.net/#System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs,105

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

Looking at https://github.com/dotnet/runtime/blob/603ebe97e2202bfa81d26cda146bddd53fde7f6b/src/coreclr/src/vm/ecalllist.h#L913 we can see it points to:

https://github.com/dotnet/runtime/blob/603ebe97e2202bfa81d26cda146bddd53fde7f6b/src/coreclr/src/classlibnative/bcltype/objectnative.cpp#L140

FCIMPL2(FC_BOOL_RET, ObjectNative::Equals, Object *pThisRef, Object *pCompareRef)
{
    CONTRACTL
    {
        FCALL_CHECK;
        INJECT_FAULT(FCThrow(kOutOfMemoryException););
    }
    CONTRACTL_END;

    if (pThisRef == pCompareRef)
        FC_RETURN_BOOL(TRUE);

    // Since we are in FCALL, we must handle NULL specially.
    if (pThisRef == NULL || pCompareRef == NULL)
        FC_RETURN_BOOL(FALSE);

    MethodTable *pThisMT = pThisRef->GetMethodTable();

    // If it's not a value class, don't compare by value
    if (!pThisMT->IsValueType())
        FC_RETURN_BOOL(FALSE);

    // Make sure they are the same type.
    if (pThisMT != pCompareRef->GetMethodTable())
        FC_RETURN_BOOL(FALSE);

    // Compare the contents (size - vtable - sync block index).
    DWORD dwBaseSize = pThisRef->GetMethodTable()->GetBaseSize();
    if(pThisRef->GetMethodTable() == g_pStringClass)
        dwBaseSize -= sizeof(WCHAR);
    BOOL ret = memcmp(
        (void *) (pThisRef+1),
        (void *) (pCompareRef+1),
        dwBaseSize - sizeof(Object) - sizeof(int)) == 0;

    FC_GC_POLL_RET();

    FC_RETURN_BOOL(ret);
}
FCIMPLEND

Upvotes: 1

Greg
Greg

Reputation: 16680

The default implementation of Equals supports reference equality for reference types, and bitwise equality for value types. Reference equality means the object references that are compared refer to the same object. Bitwise equality means the objects that are compared have the same binary representation.

http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx

Upvotes: 66

UshaP
UshaP

Reputation: 1291

it checks for reference unless you override equals

Upvotes: 9

Related Questions