0

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?
    }
}
2

4 Answers 4

10

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.

Sign up to request clarification or add additional context in comments.

3 Comments

agreed, the mathematical equation is insoluble except when x = y
@TA, The equation isn't insoluable, exactly. return 1; fits all the necessary conditions of a working GetHashCode, it's just that performance will be terrible.
@tnyfst: Hence my "Well, not apart from returning a constant value" bit.
8

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: [email protected]

Person b:
    name: steve
    email: [email protected]

Person c:
    name: steve
    email: [email protected]

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.

1 Comment

Well spotted. Not sure how I overlookd that.
0

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.

Comments

-4

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.

9 Comments

-1: This does not make sense, and will not work in Jon Skeet's example unless GetHashCode is allowed to vary between calls, which is must not.
@Brian, There are many rules to implementing GetHashCode(). If you and the OP really want to know here they are:1. If two objects are equal as defined by the operator== they MUST generate the same hash code. 2. GetHashCode() must be instance invariant. 3. The Hash function should generate a random distribution across the range of integers.
Now you don't have to (and should not) implement GetHashcode unless you intend to use your type as a key in a Dictionary or a HashSet. But seeing that the OP didn't mention this need nor care about the other rules, I don't see why you're hung up on "must not change" when there is no mention of his customer type being immutable.
@Shiv: My explanation was a bit imprecise, as are the rules you are listing. My point about "must not change" was that the HashCode should not change unless the return of the Equals function will return, which is required ( See MSDN ). Your scheme will break if you don't allow calling the Equals method to change the hashcode.
Though maybe I'm misunderstanding your proposal. Maybe you're proposing calling the Equals method on every pair of Person instances in order to generate the hash code. That's still completely broken, though.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.