Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type-safe Equals()

As my (unit-)test coverage is still quite low, unfortunately, I have to find lots of errors the hard way. Therefore, during refactoring, I heavily rely on type checking of the C# compiler.

Today, I fixed a bug introduced during refactoring by missing a line with x.Equals(aThingWrappingOriginalThing). As it's bool Equals(object T), the compiler did not complain. However, 90% of the time I use Equals() directly (instead through the BCL), I intend to logically compare objects of the same type.

Now I'm wondering why I've never seen someone promoting a type-safe version of Equals() for such situations (in C#). Is there a best practice for this?

I'm tempted to use an extension method for those comparisions, like so:

public static bool SafeEquals<T>(this T a, T b)
{
    if (a == null) return b == null;
    return a.Equals(b);
}
public static bool SafeEquals<X>(this IEquatable<X> a, IEquatable<X> b)
{
    if (a == null) return b == null;
    return a.Equals(b);
}

Could these be optimized?

Here's the only blog post about the topic I found, for java: http://rickyclarkson.blogspot.com/2006/12/making-equalsobject-type-safe.html

like image 748
Equalizer Avatar asked Jul 10 '12 20:07

Equalizer


2 Answers

You are looking for

EqualityComparer<T>.Default.Equals(x,y);

this supports IEquatable<T> (if implemented), else uses the potentially-boxing Equals(object); it supports classes and structs, with expected null-behaviour for both, including support for Nullable<T> (without boxing).

like image 80
Marc Gravell Avatar answered Oct 21 '22 06:10

Marc Gravell


What I see looks good to me.

My 2 cents: I think it would be simpler to skip the null checks, and use this:

public static bool SafeEquals<T>(this T a, T b)
{
    return object.Equals(a, b);
}

There are very few cases in which that would deviate from intended behaviour. One of them is when Equals returns false when both objects are the same object (which should never happen anyway).

For reference, here is the decompiled object.Equals, so you can see for yourself what happens.

public static bool Equals(object objA, object objB)
{
    return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB)));
}
like image 27
Kendall Frey Avatar answered Oct 21 '22 07:10

Kendall Frey