Question

I have a class Person for which I have to override the Equals and GetHashCode method. Two person objects are equals if the Name matches OR if the Email matches. What's a good way of doing this with a considerably efficient hash function?

class Person
{
    string Name
    string Email

    public override Equals(object obj)
    {
        if (ReferenceEquals(obj, null))
            return false;
        if (ReferenceEquals(this, obj))
            return true;
        if (obj is Person)
        {
            Person person = (Person)obj;
            return
                (this.Name == person.Name)
                || (this.Email == person.Email);
        }
        return false;
    }

    public override GetHashCode()
    {
        // What's a good way to implement?
    }
}
Was it helpful?

Solution

You can't, really. Well, not apart from returning a constant value.

Look at it this way... all people with email "x" have to have the same hash code, because they're equal. And all people with name "y" have to have the same hash code, and so it goes on:

Name    Email    Hash
  n1       e1      h1
  n2       e1      h1 (because emails are equal
  n2       e2      h1 (because names are equal to previous)

Note how we've managed to change both the name and the email to arbitrary values, but the hash has to still be h1.

OTHER TIPS

I know that this does not answer your question, but your approach is incorrect. It is expected that if a == b, and b == c, it necessarily follows that a == c.

Person a:
    name: mike
    email: someone@website.com

Person b:
    name: steve
    email: someone@website.com

Person c:
    name: steve
    email: steve@website.com

In this example a == b, and b == c, but a != c. This is incorrect behavior. If you want to implement this behavior, it is perfectly fine to have a method other that Equals that does this comparison, but not equals.

See http://msdn.microsoft.com/en-us/library/ms173147%28VS.80%29.aspx.

Like Alex said, this is more of a business rule related thing and I wouldn't use Equals for this purpose. I'd have another method that has the implementation you have in the Equals method.

Of course, Alex mentions a hash of Name+email but that won't work for you either since Jon pointed out, it's not really something you can do given the business rules you have.

There is a way in which you can do what you're trying to do.

Let's say you have an Enum that you've defined like so

public enum MatchedOn { None, Name, Email }

Next, pull out the implementation of your Equals method into another method such that you call it from your Equals method. In this new method, set the enum to be Name if the names are equal or Email if the emails are equal or None if neither is the same.

Then in your GetHashCode implementation you can call this new method as well and then return a hashed code based on Name or Email or the combination of both.

I hope that makes sense.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top