/// <summary> /// Structural equality testing. Objects are equal if they are of the same type /// and if each field (given by the enumeration <see cref="FieldValues" />) is equal /// for the two values. /// </summary> /// <param name="obj">The value to compare to this value</param> /// <returns>True if the values are equal, false otherwise.</returns> public override bool Equals(object /*?*/ obj) { CompoundValue other = obj as CompoundValue; if ((object)other == null) { return(false); } if ((object)this == obj) { return(true); } if (this.GetType() != obj.GetType()) { return(false); } IEnumerator <IComparable> fields1 = this.FieldValues().GetEnumerator(); IEnumerator <IComparable> fields2 = other.FieldValues().GetEnumerator(); while (true) { bool hasNext1 = fields1.MoveNext(); bool hasNext2 = fields2.MoveNext(); if (hasNext1 ^ hasNext2) { return(false); // differing lengths } if (!hasNext1) { return(true); } if (!Object.Equals(fields1.Current, fields2.Current)) { return(false); } } }
/// <summary> /// Term order. Comparision is based on type and recursively on fields. /// </summary> /// <param name="obj"></param> /// <returns>-1 if less than, 0 if equal, 1 if greater than</returns> /// <exception cref="System.ArgumentException">Thrown if <paramref name="obj"/> is nonnull but is not an <c>CompoundValue</c>.</exception> public override int CompareTo(object /*?*/ obj) //^ requires obj != null ==> obj is IComparable; //^ ensures result == 0 <==> Object.Equals(this, obj); //^ ensures result == -1 || result == 0 || result == 1; { // Case 1: other obj is null if (obj == null) { return(1); // nonnull is bigger than null } CompoundValue other = obj as CompoundValue; if ((object)other == null) { throw new ArgumentException(MessageStrings.LocalizedFormat(MessageStrings.CompoundValueRequired, obj.GetType().ToString())); } // Case 2: types aren't the same, do type comparison in dictionary order Type t1 = this.GetType(); Type t2 = obj.GetType(); if (t1 != t2) { return(t1.ToString().CompareTo(t2.ToString())); } // Case 3: types are the same, look for first field that is not equal IEnumerator <IComparable> fields1 = this.FieldValues().GetEnumerator(); IEnumerator <IComparable> fields2 = other.FieldValues().GetEnumerator(); while (true) { bool hasNext1 = fields1.MoveNext(); bool hasNext2 = fields2.MoveNext(); if (hasNext1 & !hasNext2) { return(1); // longer comes after shorter } if (!hasNext1 & hasNext2) { return(-1); // shorter comes before longer } if (!hasNext1) { return(0); // items are equal } IComparable c1 = fields1.Current as IComparable; IComparable c2 = fields2.Current as IComparable; if (fields1.Current != null && c1 == null) { throw new ArgumentException(MessageStrings.LocalizedFormat(MessageStrings.ComparableTypeRequired, fields1.Current.GetType().ToString())); } if (fields2.Current != null && c2 == null) { throw new ArgumentException(MessageStrings.LocalizedFormat(MessageStrings.ComparableTypeRequired, fields2.Current.GetType().ToString())); } int fieldCompare = HashAlgorithms.CompareValues(c1, c2); if (fieldCompare != 0) { return(fieldCompare); } } }