tags:

views:

307

answers:

4

For a reference type (class) like Point3 (for example), is this an overkill, lacking:

#region System.Object Members

public override bool Equals ( object obj )
{
        //return this == ( Point3 ) obj;

        if ( obj == null )
        {
                return false;
        }

        if ( this.GetType ( ) != obj.GetType ( ) )
        {
                return false;
        }

        return this.Equals ( ( Point3 ) obj );
}

public override int GetHashCode ( )
{
        return this.X.GetHashCode ( ) ^ this.Y.GetHashCode ( ) ^ this.Z.GetHashCode ( );
}

public override string ToString ( )
{
        return String.Format ( "[{0}, {1}, {2}]", this.X, this.Y, this.Z );
}

#endregion

#region IEquatable<Point3> Members

public bool Equals ( Point3 other )
{
        if ( other == null )
        {
                return false;
        }

        if ( ReferenceEquals ( this, other ) )
        {
                return true;
        }

        if ( this.GetHashCode ( ) != other.GetHashCode ( ) )
        {
                return false;
        }

        if ( !base.Equals ( other ) )
        {
                return false;
        }

        return this == other;
}

#endregion

public static bool operator == ( Point3 v0, Point3 v1 )
{
        return ( v0.X.IsEqual ( v1.X ) ) && ( v0.Y.IsEqual ( v1.Y ) ) && ( v0.Z.IsEqual ( v1.Z ) );
}

public static bool operator != ( Point3 v0, Point3 v1 )
{
        return !( v0 == v1 );
}

Please make adjustments or post a new one for both value and reference types, that I can use in my base types (value and reference) without thinking too much every time I implement it again.

EDIT: This is for immutable types.

+3  A: 

this.GetType ( ) != obj.GetType ( )

That will be slow. Use obj is Type rather.

ReferenceEquals is pointless for valuetypes, which I assume Point3 is.

I would also not bother with the hash code check in equality procedures.

leppie
+4  A: 

Well, first of all, don't fall into the trap of producing a hash code using XOR as your combination operator.

Otherwise, you'll have the following problems, where HC(x) means "the hash code of object/value x":

HC(a,b) = HC(b,a)
HC(a,a) = HC(b,b) = 0

Instead, opt for something that at least takes the order of the values into account, like the following:

hashcode = 23 // prime number
for each sub-value of the object, do:
    hashcode = hashcode * 31 // another prime number
    hashcode = hashcode + the hashcode of the sub-value

This will preserver ordering, as much as possible.

Lasse V. Karlsen
Why a prime number?
configurator
You'll have to ask Knuth about that actually. All I know is that it produces values that are generally less prone to collisions. At the very least (again, Knuth), you should choose two numbers that are coprime, that is, have no factors in common.
Lasse V. Karlsen
+2  A: 

If you are really into performance and your values x, y and z do not change (at least very often), while you do a lot of comparisons, you could pre-calculate your hashcode. Then use it very early during your equality-comparison.

But the best in this case is: use a profiler to find the real bottleneck.

tanascius
No you can't use a Hash to do a reliable Equality check.
Henk Holterman
If the hashvalues are unequal you can stop to compare types or anything else ... in most cases you will get negative hits ... and then the hashcode is a very quick mechanism
tanascius
+2  A: 

ALso, if you are creating your own Equals method, you should think about implementing IEquatable. This gives you a nice equality method to compare the same type, and often you can cut down the Equals(object) method to (for reference types):

public override Equals(object other)
{
    Point3 otherP = other as Point3;
    return otherP != null && Equals(otherP); // calls the Equals(Point3) method
}

As well as being a bit nicer, this cuts down a box operation if the type is a struct - provided the IEquatable implementation is implicit, code will automatically use the typed Equals(Point3) method, rather than using Equals(object) that involves a box operation (and presumably an unbox actually inside that method)

thecoop