Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using "Equals" for valuetypes in C# seems not a good idea, is it?

I red that the default behavior for "Equals" in value types (structs) is using reflection to compare the content of the two values, so it's recommended to override the Equals operator for efficiency if performance is important.

But it seems that the signature of Equals is :

public override bool Equals( object ob )

Which means that even if i'll override this method, i'll still have boxing when i compare value type because the parameter must be of an "object" type.

Am i correct ? is boxing does occur ? Should i use only == operator for value type ?

EDIT : And a little side question, why when i override == it should be static and get 2 parameters instead of the more intuitive form of not being static and comparing "this" with one parameter ?

like image 838
OopsUser Avatar asked Feb 18 '23 01:02

OopsUser


1 Answers

In addition to overriding Object.Equals() you should implement IEquatable<T>, where T is your type itself. IEquatable<T>.Equals() accepts an argument of type T.

If you implement the interface implicitly (and why wouldn't you?) then the more specific method accepting the T-typed argument will be used when possible, and in this case no boxing will occur. (This is true if you overload Equals() and don't implement the interface, but there is no reason not to implement the interface in this case.)

This is the pattern I usually use when implementing value type equality:

struct Foo : IEquatable<Foo>
{
    public bool Equals(Foo other)
    {
        // Do your equality test here.
        throw new NotImplementedException();
    }

    public override bool Equals(object other)
    {
        if (other != null && other is Foo) {
            return Equals((Foo)other);
        }

        return false;
    }

    // If you also want to overload the equality operator:
    public static bool operator==(Foo a, Foo b)
    {
        return a.Equals(b);
    }

    public static bool operator!=(Foo a, Foo b)
    {
        return !a.Equals(b);
    }
}

Of course, don't forget to override Object.GetHashCode() too.


Note that when using the Equals(object) method, only the argument is boxed. The object you are invoking on will not be boxed, unless you convert it to object (or an interface type) first. One of the ldloca, ldflda, or ldsflda instructions will be emitted (as appropriate) for the object you invoke on, and the other would be boxed (in the absence of a more-specific overload).

like image 118
cdhowie Avatar answered Mar 15 '23 15:03

cdhowie