How to best implement Equals for custom types?

前端 未结 10 722
春和景丽
春和景丽 2020-11-28 08:41

Say for a Point2 class, and the following Equals:

public override bool Equals ( object obj )

public bool Equals ( Point2 obj )

This is the

10条回答
  •  半阙折子戏
    2020-11-28 08:59

    Slight variants of forms already posted by several others...

    using System;
    ...
    public override bool Equals ( object obj ) {
       return Equals(obj as SomeClass);
    }
    
    public bool Equals ( SomeClass someInstance ) {
        return Object.ReferenceEquals( this, someInstance ) 
            || ( !Object.ReferenceEquals( someInstance, null ) 
                && this.Value == someInstance.Value );
    }
    
    public static bool operator ==( SomeClass lhs, SomeClass rhs ) {
        if( Object.ReferenceEquals( lhs, null ) ) {
            return Object.ReferenceEquals( rhs, null );
        }
        return lhs.Equals( rhs );
        //OR
        return Object.ReferenceEquals( lhs, rhs )
                || ( !Object.ReferenceEquals( lhs, null ) 
                    && !Object.ReferenceEquals( rhs, null )
                    && lhs.Value == rhs.Value );
    }
    
    public static bool operator !=( SomeClass lhs, SomeClass rhs ) {
        return !( lhs == rhs );
        // OR
        return ( Object.ReferenceEquals( lhs, null ) || !lhs.Equals( rhs ) )
                && !Object.ReferenceEquals( lhs, rhs );
    }
    

    Trying to find a way to implement operator == using Equals to avoid duplicating the value comparison logic... without any redundant tests (ReferenceEquals calls w/ the same parameters) or unnecessary tests (this can't be null in the instance.Equals method) and without any explicit conditionals ("ifs"). More of a mind teaser than anything useful.

    Closest I can think of is this, but it feels like it should be possible without an extra method :)

    public bool Equals ( SomeClass someInstance ) {
        return Object.ReferenceEquals( this, someInstance ) 
            || (!Object.ReferenceEquals( someInstance, null ) && EqualsNonNullInstance( someInstance );
    }
    
    public static bool operator ==( SomeClass lhs, SomeClass rhs ) {
        return Object.ReferenceEquals( lhs, rhs ) 
        || ( !Object.ReferenceEquals( lhs, null ) && !Object.ReferenceEquals( rhs, null ) && lhs.EqualsNonNullInstance( rhs ) );
    }
    
    //super fragile method which returns logical non-sense
    protected virtual bool EqualsNonNullInstance ( SomeClass someInstance ) {
        //In practice this would be a more complex method...
        return this.Value == someInstance.Value;
    }
    

    Remembering how tedious and error prone this all is (I'm almost sure there's an error in the above code... which still sucks because who wants to subclass a Type just to make equality checks slightly simpler?), going forward I think I'll just create some static methods that handle all the null checks and accept a delegate or require and interface to perform the comparison of values (the only part that really changes Type to Type).

    It'd be great if we could just add attributes onto the fields/properties/methods that need to be compared and let the compiler/runtime handle all the tedium.

    Also make sure GetHashCode() values are equal for any instances in which which .Equals(object) returns true or crazy shit can happen.

提交回复
热议问题