private static bool Match(object originalValue, object copyValue) { // If a custom IMatchable description exists use it to determine if there is a match IProjMatchable originalMatch = originalValue as IProjMatchable; IProjMatchable copyMatch = copyValue as IProjMatchable; if (originalMatch != null && copyMatch != null) { bool res = originalMatch.Matches(copyMatch); return(res); } // Strings are enumerable, so test them first, since string.Equals should be faster than // cycling through each character. string origString = originalValue as string; if (origString != null) { string mString = copyValue as string; if (mString == null) { return(false); } return(origString.Equals(mString)); } // If the object is an enumeration, test the members of the enumeration. // If any members fail the match test, then the whole collection fails the match. IEnumerable originalList = originalValue as IEnumerable; if (originalList != null) { IEnumerable copyList = copyValue as IEnumerable; if (copyList != null) { IEnumerator e = copyList.GetEnumerator(); e.MoveNext(); foreach (object originalItem in originalList) { if (Match(originalItem, e.Current) == false) { return(false); } e.MoveNext(); } } return(true); } if (originalValue == null && copyValue == null) { return(true); } // If the objects are not collections and are not IMatchable, the only remaining thing we can // realistically test is simple equality. // Don't use == here! It will always be false for boxed value types. return(originalValue != null && (originalValue.Equals(copyValue))); }
/// <summary> /// This tests the public properties from the two objects. If any properties implement /// the IMatchable interface, and do not match, this returns false. If any public /// properties are value types, and they are not equal, then this returns false. /// </summary> /// <param name="self">This matchable item </param> /// <param name="other">The other item to compare to this item</param> /// <returns>Boolean, true if there is a match</returns> public static bool Matches(this IProjMatchable self, IProjMatchable other) { List <string> ignoreMe; return(self.Matches(other, out ignoreMe)); }
/// <summary> /// Compares the properties of this object with the specified IMatchable other. /// This does not test every property of other, but does test every property /// of this item. As long as the other item has corresponding properties /// for every property on this item, the items are said to match. /// The IMatchable interface allows custom definitions of matching. /// For collections to match, all of their sub-members must match. /// </summary> /// <param name="other"></param> /// <param name="mismatchedProperties"></param> /// <returns></returns> public bool Matches(IProjMatchable other, out List<string> mismatchedProperties) { mismatchedProperties = new List<string>(); return OnMatch(other, mismatchedProperties); }
/// <summary> /// This gives sub-classes the chance to directly override, control or otherwise tamper /// with the matching process. This is also where normal matching is performed, /// so to replace it, simply don't call the base.OnMatch method. To tweak the results, /// the base method should be performed first, and the results can then be modified. /// </summary> /// <param name="other"></param> /// <param name="mismatchedProperties"></param> /// <returns></returns> protected virtual bool OnMatch(IProjMatchable other, List<string> mismatchedProperties) { Type original = GetType(); Type copy = other.GetType(); // Public Properties ------------------------------------------------------ PropertyInfo[] originalProperties = original.GetProperties(BindingFlags.Public | BindingFlags.Instance); PropertyInfo[] copyProperties = copy.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (PropertyInfo originalProperty in originalProperties) { if (copyProperties.Contains(originalProperty.Name) == false) { mismatchedProperties.Add(originalProperty.Name); continue; } PropertyInfo copyProperty = copyProperties.GetFirst(originalProperty.Name); if (copyProperty == null) { // The name of the property was not found on the other object mismatchedProperties.Add(originalProperty.Name); continue; } object originalValue = originalProperty.GetValue(this, null); object copyValue = copyProperty.GetValue(other, null); if (Match(originalValue, copyValue) == false) { mismatchedProperties.Add(originalProperty.Name); } } // Public Fields --------------------------------------------------------- FieldInfo[] originalFields = original.GetFields(BindingFlags.Public | BindingFlags.Instance); FieldInfo[] copyFields = copy.GetFields(BindingFlags.Public | BindingFlags.Instance); foreach (FieldInfo originalField in originalFields) { if (copyFields.Contains(originalField.Name) == false) { mismatchedProperties.Add(originalField.Name); continue; } FieldInfo copyField = copyFields.GetFirst(originalField.Name); if (copyField == null) { mismatchedProperties.Add(originalField.Name); continue; } object originalValue = originalField.GetValue(this); object copyValue = copyField.GetValue(other); if (Match(originalValue, copyValue) == false) { mismatchedProperties.Add(originalField.Name); } } if (mismatchedProperties.Count > 0) { return false; } return true; }
/// <summary> /// This tests the public properties from the two objects. If any properties implement /// the IMatchable interface, and do not match, this returns false. If any public /// properties are value types, and they are not equal, then this returns false. /// </summary> /// <param name="self">This matchable item </param> /// <param name="other">The other item to compare to this item</param> /// <returns>Boolean, true if there is a match</returns> public static bool Matches(this IProjMatchable self, IProjMatchable other) { List<string> ignoreMe; return self.Matches(other, out ignoreMe); }
/// <summary> /// Compares the properties of this object with the specified IMatchable other. /// This does not test every property of other, but does test every property /// of this item. As long as the other item has corresponding properties /// for every property on this item, the items are said to match. /// The IMatchable interface allows custom definitions of matching. /// For collections to match, all of their sub-members must match. /// </summary> /// <param name="other"></param> /// <param name="mismatchedProperties"></param> /// <returns></returns> public bool Matches(IProjMatchable other, out List <string> mismatchedProperties) { mismatchedProperties = new List <string>(); return(OnMatch(other, mismatchedProperties)); }
/// <summary> /// This gives sub-classes the chance to directly override, control or otherwise tamper /// with the matching process. This is also where normal matching is performed, /// so to replace it, simply don't call the base.OnMatch method. To tweak the results, /// the base method should be performed first, and the results can then be modified. /// </summary> /// <param name="other"></param> /// <param name="mismatchedProperties"></param> /// <returns></returns> protected virtual bool OnMatch(IProjMatchable other, List <string> mismatchedProperties) { Type original = GetType(); Type copy = other.GetType(); // Public Properties ------------------------------------------------------ PropertyInfo[] originalProperties = original.GetProperties(BindingFlags.Public | BindingFlags.Instance); PropertyInfo[] copyProperties = copy.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (PropertyInfo originalProperty in originalProperties) { if (copyProperties.Contains(originalProperty.Name) == false) { mismatchedProperties.Add(originalProperty.Name); continue; } PropertyInfo copyProperty = copyProperties.GetFirst(originalProperty.Name); if (copyProperty == null) { // The name of the property was not found on the other object mismatchedProperties.Add(originalProperty.Name); continue; } object originalValue = originalProperty.GetValue(this, null); object copyValue = copyProperty.GetValue(other, null); if (Match(originalValue, copyValue) == false) { mismatchedProperties.Add(originalProperty.Name); } } // Public Fields --------------------------------------------------------- FieldInfo[] originalFields = original.GetFields(BindingFlags.Public | BindingFlags.Instance); FieldInfo[] copyFields = copy.GetFields(BindingFlags.Public | BindingFlags.Instance); foreach (FieldInfo originalField in originalFields) { if (copyFields.Contains(originalField.Name) == false) { mismatchedProperties.Add(originalField.Name); continue; } FieldInfo copyField = copyFields.GetFirst(originalField.Name); if (copyField == null) { mismatchedProperties.Add(originalField.Name); continue; } object originalValue = originalField.GetValue(this); object copyValue = copyField.GetValue(other); if (Match(originalValue, copyValue) == false) { mismatchedProperties.Add(originalField.Name); } } if (mismatchedProperties.Count > 0) { return(false); } return(true); }