C#: Generics Equality

When comparing objects using generics in C#, the behaviour is slightly different to normal comparison behaviour – notably that the compiler will default to using the more generic equals method equals(object obj)) as opposed to specific type based equals that you may have declared in a class. To overcome this, your class must implement the generic IEquatable<T> interface (instead of just overriding / overloading the equals method). A simple example is shown below:

internal class Foo : IEquatable<Foo>
{
    public int Property1 { get; set; }
    public bool Equals(Foo obj)
    {
        if (!this.Property1.Equals(obj.Property1)) return false;
        return true;
    }
}

internal class DoSomething
{
    public void Something()
    {
        var thing1 = new Foo { Property1 = 23 };
        var thing2 = new Foo { Property1 = 23 };
        this.Compare<Foo>(thing1, thing2);
    }

    private void Compare<T>(T expected, T actual) where T : IEquatable<T>
    {
        if (expected.Equals(actual))
            Console.WriteLine(“Input was equal”);
        else
            Console.WriteLine(“Input was not equal”);
    }
}

Note that this become more complicated however when comparing an instance of a base class to an instance of a deriving class. Normally you would probably want to do this using the base class implementation of equals, however some extra work is required to achieve the correct behaviour with generics (notably a constraint on your comparison method and a cast to IEquatable<T>.

internal class Foo : IEquatable<Foo>
{
    public int Property1 { get; set; }

    public bool Equals(Foo obj)
    {
        if (!this.Property1.Equals(obj.Property1)) return false;
        return true;
    }
}

internal class Bar : Foo
{
    public string Property2 { get; set; }
}

internal class DoSomething
{
    public void Something()
    {
        var thing1 = new Foo { Property1 = 23 };
        var thing2 = new Bar { Property1 = 23, Property2 = “Hello” };
        this.Compare<Foo, Bar> (thing1, thing2);
    }

    private void Compare<T, V>(T expected, V actual) where V : class, T, IEquatable<T>
    {
        if (((IEquatable<T>)expected).Equals(actual))
            Console.WriteLine(“Input was equal”);
        else
            Console.WriteLine(“Input was not equal”);
    }
}

Note that this link discusses this in more detail.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>