Improving Struct Equality Performance in C#

The equality performance of struct equality comparisons can be improved by overriding .Equals(). This is especially true if the structs we are comparing contain reference type fields.

By default, the equality of structs is automatically determined by doing a byte-by-byte comparison of the two struct objects in memory – only when the structs don’t contain any reference types. When the structs contain reference type fields then reflection is used to compare the fields of the two struct objects which results in slower performance.

This chart show the relative performance of the default equality of a struct that contains only value types against a struct that also contains a reference type:

struct equality performance chart

This chart is based on performing an equality test 10000000 times and comparing the time in milliseconds. I have deliberately omitted the specific numbers as I want to concentrate on the relative differences.

These are the structs that were compared:

internal struct WithRefNoOverride
{
    public int X { get; set; }
    public int Y { get; set; }
    public string Description { get; set; }
}

internal struct NoRefNoOverride
{
    public int X { get; set; }
    public int Y { get; set; }
}

If we override .Equals() to provide our own definition of what equality means, our method will be used rather that the default reflection-based mechanism:

internal struct WithRefWithOverride
{
    public int X { get; set; }
    public int Y { get; set; }
    public string Description { get; set; }

    public override bool Equals(object obj)
    {
        if (!(obj is WithRefWithOverride))            
            return false;           

        var other = (WithRefWithOverride) obj;

        return X == other.X &&
              Y == other.Y &&
              Description == other.Description;
    }

    // GetHashCode override and == != operators omitted for brevity
}

If we run the test again, comparing the performance of WithRefNoOverride against WithRefWithOverride we get the following results:

struct equality performance chart

Implementing our own custom overridden .Equals() means that reflection will not be used, instead our .Equals() code is used instead.

As with all things performance related these differences may or may not be important to the application you’re writing.

 

For more C# tips, check out my Pluralsight C# Tips and Traps 2 course.

Comments (1) -

  • vasea

    10/23/2013 5:49:58 PM | Reply

    Nice article. I think implementing IEquatable interface is worth mentioning in your article. It solves the boxing issue and improves the performance of generic collections.

Pingbacks and trackbacks (3)+

Add comment

Loading