Please explain the technique used in this code to test Object Equality and Identity

221 views Asked by At

Please explain the technique used in this code to test Object Equality and Identity.

Better, if you can supply me any web-link/book-reference for detailed discussion.

[Serializable]
    public abstract class BusinessObject<T> : IBusinessObject where T : BusinessObject<T>
    {
        private int? requestedHashCode;

        public virtual int ID { get; set; }

        public virtual bool Equals(IBusinessObject other)
        {
            if (null == other || !GetType().IsInstanceOfType(other))
            {
                return false;
            }
            if (ReferenceEquals(this, other))
            {
                return true;
            }

            bool otherIsTransient = Equals(other.ID, default(T));
            bool thisIsTransient = IsTransient();
            if (otherIsTransient && thisIsTransient)
            {
                return ReferenceEquals(other, this);
            }

            return other.ID.Equals(ID);
        }

        protected bool IsTransient()
        {
            return Equals(ID, default(T));
        }

        public override bool Equals(object obj)
        {
            var that = obj as IBusinessObject;
            return Equals(that);
        }

        public override int GetHashCode()
        {
            if (!requestedHashCode.HasValue)
            {
                requestedHashCode = IsTransient() ? base.GetHashCode() : ID.GetHashCode();
            }
            return requestedHashCode.Value;
        }
}

What is a transient object?

2

There are 2 answers

4
Thomas Levesque On BEST ANSWER
  • it first checks if other is an instance of the same type as the current object. If not, they're not equal
  • it then performs a reference equality to check if other and the current object are the same instance. If they are, obviously they are equal
  • If both other and the current object are transient (i.e. not yet persisted), they don't have an ID, so they can't be compared by ID. Instead, they are compared by reference. (as noted by Marc Gravell in the comments, the test to check if the object is transient is broken; it doesn't make sense to compare an int to default(T))
  • Eventually, their IDs are compared; the objects are considered equal if they have the same ID
0
Marc Gravell On

I think what the code is trying to do is say "has it got an ID yet", i.e. a "transient" object might (if I read the code's intent correctly) be one that is not yet saved to the DB. Then equality is defined as:

  • if it has an ID, does it match? (even for different instances of the same type)
  • if it doesn't have an ID, is it the same object instance (reference)

unfortunately the implementation looks completely broken, as Equals(ID, default(T)) is meaningless when T is something completely different (a BusinessObject<T>) - hence default(T) will always be null and ID will never be null (it is not nullable). So nothing will ever report as transient.

Additionally, this code:

if (null == other || !GetType().IsInstanceOfType(other))

is hugely inefficient. I suspect something involving as would be far preferable, but again: the code looks so... tortured... that I'm loathe to second-guess the intent.