views:

80

answers:

4

For an object with properties A, B, C, D, StartDate and EndDate if I wanted to implement something where any two objects are equal if they have identical A, B and C and overlapping date range, how would that be done?

I have tried creating an EqualityComparer like so

    public override bool Equals(RateItem x, RateItem y)
    {
        bool equal = true;
        if ((x.A != y.A || x.B != y.B || x.C != y.C ||
            (x.StartDate < y.StartDate && x.EndDate <= y.StartDate) ||
            (x.StartDate > y.StartDate && y.EndDate <= x.StartDate)))
        { equal = false; }
        return equal;
    }

But it seems lots of places in the framework ignore Equals and use GetHashCode and the documentation is not clear on that at all. When I go to implement GetHashCode I don't know how to make the HashCodes turn out the same without ignoring the dates.

To make it a little more concrete this has to do with project management and rates. I want to implement a business rule that the same person on the same project in the same role can't have to different rates during the same time period. So Bob on Project DeathMarch in the role of DBA can only have one effective bill rate at any given time to log his time. If he needed to log some hours in the role of QA analyst at a different rate during the same time period that is OK. This is a massive pre-existing system so changing the domain object structure is not an option.

+2  A: 

This is not possible.

Equality in .Net must be transitive, meaning that if a == b and b == c, then a == c.

SLaks
You can define your own `IsInConflictWith` kind of method and do a n^2 test. A better solution is to just have it all in a single `DetectConflicts` method that orders them by `StartDate` and then checks for overlaps with a single pass.
Stephen Cleary
A: 

If you are using the items in a hashtable then their GetHashCode method will be used initially to test for equality and if their hashes are found to be equal a call to their Equals method will be made to establish whether they are equal.

From the documentation:

"But is that enough for the Hashtable to determine they are identical objects? Unfortunately, no. If the Hashtable finds two objects with the same hash, it calls their Equals method to see whether the two objects are in fact equal. Again, the default implementation of Object.Equals will return false if the two objects are two different instances of the same class. So we need to also add an override of the Equals method to our class.

Ando
A: 

Maybe try to hash the results of dates comparisons. I mean not to hash the values of StartDate and EndDate directly, but hash the results of whole expressions:

(x.StartDate < y.StartDate && x.EndDate <= y.StartDate)

and

(x.StartDate > y.StartDate && y.EndDate <= x.StartDate)
eigenein
+1  A: 

It is possible. The only rule for GetHashCode is that A.GetHashCode() must equal B.GetHashCode() if A == B. The opposite, if A == B A.GetHashCode() == B.GetHashCode() does not have to be true.

So you can simply make GetHashCode like so

public override int GetHashCode()
{
    return A.GetHashCode() ^ B.GetHashCode() ^ C.GetHashCode();
}

GetHashCode is not for identity!! It is used for grouping 'similar' objects.

Proof:

string a = "a";
string b = "EUKCnPMLpp";
Console.WriteLine("a = '{0}', b = '{1}', Same = {2}", a, b, a == b);
Console.WriteLine("a.GetHashCode() = {0}, b.GetHashCode() = {1}, Same = {2}", a.GetHashCode(), b.GetHashCode(), a.GetHashCode() == b.GetHashCode());
Tergiver
Your first sentence has a mistake.
SLaks
This won't help. There are a potentially infinite number of non-equal but overlapping objects.
SLaks
There is no mistake on my part. Your mistake is in confusing identity with the purpose of GetHashCode. If you're going to refute the statement, provide a concrete example.
Tergiver
Edited to provide proof that my statement is true.
Tergiver