/// <summary> /// Returns true if two objects match equality /// </summary> /// <param name="typeSupport">The extended type for the left object</param> /// <param name="left"></param> /// <param name="right"></param> /// <returns></returns> private bool CompareForObjectEquality(ExtendedType typeSupport, object left, object right) { // order of precedence: IEquatable => Equals => (==) // if the object implements IEquatable, use it var hasIEquatable = typeSupport.Implements(typeof(IEquatable <>)); if (hasIEquatable) { var equatableMethod = typeSupport.Methods?.FirstOrDefault(x => x.Name == "Equals" && x.Parameters.Any(y => y.ParameterType == typeSupport.Type)); var isEquatable = (bool)equatableMethod?.MethodInfo.Invoke(left, new object[] { right }) == true; if (isEquatable) { return(true); // no differences found } } else { // if the object overrides Equals(), use it var hasEqualsOverride = typeSupport.Methods?.Any(x => x.Name == "Equals" && x.IsOverride) == true; if (hasEqualsOverride) { if (left.Equals(right)) { return(true); // no differences found } } else { // if the object overrides the equality operator (==), use it var hasEqualityOperator = typeSupport.Methods?.Any(x => x.Name == "op_Equality" && x.IsOperatorOverload) == true; if (hasEqualityOperator) { var operatorMethod = typeSupport.Methods?.FirstOrDefault(x => x.Name == "op_Equality" && x.Parameters.All(y => y.ParameterType == typeSupport.Type)); var isEqual = (bool)operatorMethod?.MethodInfo.Invoke(left, new object[] { left, right }) == true; if (isEqual) { return(true); // no differences found } } } } return(false); }