EntitySet.Contains – uses Reference comparisons - Addendum

I realised whilst reviewing some code that you can also implement the IEquatable<T> interface as well just overriding the Equals (or indeed, in place of doing that).

So, back to our Simple class, we could actually write it as such:

internal class Simple : IEquatable<Simple>
{
    public int TheInt { get; set; }
    public string TheString { get; set; }
 
    public Simple(int theInt, string theString)
    {
        TheInt = theInt;
        TheString = theString;
    }
 
    public bool Equals(Simple other)
    {
        if(other == null)
            return false;
 
        return TheInt == other.TheInt && string.Equals(TheString, other.TheString);
    }
}
 

This will work perfectly in a collection situation (though again, not the EntitySet), but will fail with the extension method we wrote last time… How?

Well, let’s say we perform the same test as in the last post:

public static void Run()
{
    EntitySet<Simple> simpleEs = new EntitySet<Simple>
                             {
                                 new Simple(1, "1"),
                                 new Simple(2, "2")
                             };
 
    Simple s2 = new Simple(2, "2");
    
    Console.WriteLine("Contains ES? " + simpleEs.Contains(s2));
    Console.WriteLine("Contains ES? " + simpleEs.ContainsUsingEquals(s2));
}

We will get the output:

Contains ES? false
Contains ES? false

Which isn’t what we want. Clearly when in our extension method we call:

e.Equals(t)

We are only calling the normal Equals method. We could modify this to read:

((IEquatable<T>)e).Equals(t)

Which would work as long as it was IEquatable<T> (in which case we’d be better off forcing our extension method to only work on objects implementing that interface:

public static bool ContainsUsingEquals(this EntitySet<T> es, T t)
    where T : class, IEquatable<T>
{ /**/ }

But that seems a bit limiting, so instead I modified the extension to just cover both scenarios. It will attempt to use the IEquatable<T> implementation first, and it that’s not there, use the original equals:

 

public static bool ContainsUsingEquals<T>(this EntitySet<T> es, T t)
    where T : class
{
    if (t is IEquatable<T>)
    {
        foreach (var e in es)
            if (((IEquatable<T>)t).Equals(e))
                return true;
    }
    else
    {
        foreach (var e in es)
            if (t.Equals(e))
                return true;
    }
    return false;
}

Of course it might be more efficient to do the cast of the ‘t’ to IEquatable<T> earlier and use the casted version rather than casting it each time…

meh

Print | posted @ Thursday, March 12, 2009 4:03 PM

Comments on this entry:

No comments posted yet.

Post A Comment
Title:
Name:
Email:
Comment:
Verification: