/// <summary> /// Compares two comments using the indicated comparison options. /// </summary> /// <param name="c1">The first comment to compare.</param> /// <param name="c2">The second comment to compare.</param> /// <param name="options">The options to use in the comparison.</param> /// <returns>true if the comments are equal, false otherwise.</returns> public static bool DeepEquals(this XComment c1, XComment c2, ComparisonOptions options) { if ((c1 ?? c2) == null) return true; if ((c1 == null) || (c2 == null)) return false; // They are not both null, so if either is, then the other isn't return c1.Value == c2.Value; }
/// <summary> /// Compares two texts using the indicated comparison options. /// </summary> /// <param name="t1">The first text to compare.</param> /// <param name="t2">The second text to compare.</param> /// <param name="options">The options to use in the comparison.</param> /// <returns>true if the texts are equal, false otherwise.</returns> public static bool DeepEquals(this XText t1, XText t2, ComparisonOptions options) { if ((t1 ?? t2) == null) return true; if ((t1 == null) || (t2 == null)) return false; // They are not both null, so if either is, then the other isn't return ((t1.NodeType == t2.NodeType) && (t1.Value == t1.Value)); }
internal override int GetHashCode(ComparisonOptions options) { throw new NotImplementedException(); }
public static IEqualityComparer <SymbolKey> GetComparer(ComparisonOptions options) { return(EnsureInitialized(ref s_cachedComparers[options.FlagsValue], options)); }
private SymbolKeyComparer(ComparisonOptions options) { _options = options; }
/// <summary> /// Compare two objects for value differences /// </summary> /// <param name="left">Object A</param> /// <param name="right">Object B</param> /// <param name="comparisonOptions">Specify the comparison options</param> /// <param name="diffOptions">Specify custom diff options</param> /// <returns></returns> public static ICollection <Difference> Diff(this object left, object right, ComparisonOptions comparisonOptions, DiffOptions diffOptions) { return(Diff(left, right, DiffProvider.DefaultMaxDepth, comparisonOptions, diffOptions)); }
internal override bool Equals(SymbolKey other, ComparisonOptions options) { return ReferenceEquals(this, other); }
/// <summary> /// Compares two names. /// </summary> /// <param name="n1">The first name to compare.</param> /// <param name="n2">The second name to compare.</param> /// <param name="options">The options to use in the comparison.</param> /// <returns>true if the elements are equal, false otherwise.</returns> private static bool CompareNames(XName n1, XName n2, ComparisonOptions options) { // Compare the name if ((n1.LocalName != n2.LocalName) || (n1.Namespace != n2.Namespace)) return false; else if ((options & ComparisonOptions.NamespacePrefix) == ComparisonOptions.NamespacePrefix) if (n1.NamespaceName != n2.NamespaceName) return false; return true; }
/// <summary> /// Get the differences between two objects /// </summary> /// <param name="propertyName">The name of the property being compared</param> /// <param name="propertyType">The type of property being compared. The left property is assumed unless allowCompareDifferentObjects=true</param> /// <param name="typeConverter">An optional TypeConverter to treat the type as a different type</param> /// <param name="left">The left object to compare</param> /// <param name="right">The right object to compare</param> /// <param name="parent">The parent object</param> /// <param name="differences">A list of differences currently found in the tree</param> /// <param name="currentDepth">The current depth of the tree recursion</param> /// <param name="maxDepth">The maximum number of tree children to recurse</param> /// <param name="objectTree">A hash table containing the tree that has already been traversed, to prevent recursion loops</param> /// <param name="options">Specify the comparison options</param> /// <param name="propertyList">A list of property names or full path names to ignore</param> /// <returns></returns> private List <Difference> GetDifferences(string propertyName, string showName, Type propertyType, TypeConverter typeConverter, object left, object right, object parent, List <Difference> differences, int currentDepth, int maxDepth, ObjectHashcodeMap objectTree, string path, ComparisonOptions options, List <string> propertyList) { if (GetPropertyInclusionState(propertyName, path, options, propertyList, null) == FilterResult.Exclude) { return(differences); } object leftValue = null; object rightValue = null; leftValue = left; if (options.BitwiseHasFlag(ComparisonOptions.AllowCompareDifferentObjects) && rightValue != null) { rightValue = GetValueForProperty(right, propertyName); } else { rightValue = right; } if (rightValue == null && leftValue != null || leftValue == null && rightValue != null) { differences.Add(new Difference((leftValue ?? rightValue).GetType(), propertyName, path, leftValue, rightValue, typeConverter)); return(differences); } if (leftValue == null && rightValue == null) { return(differences); } var propertyTypeSupport = propertyType.GetExtendedType(DefaultTypeSupportOptions); var isCollection = propertyType != typeof(string) && propertyType.GetInterface(nameof(IEnumerable)) != null; if (isCollection && options.BitwiseHasFlag(ComparisonOptions.CompareCollections)) { var genericArguments = propertyType.GetGenericArguments(); var isArray = propertyTypeSupport.IsArray; var elementType = propertyTypeSupport.ElementType; // iterate the collection var aValueCollection = (leftValue as IEnumerable); var bValueCollection = (rightValue as IEnumerable); var bValueCollectionCount = GetCountFromEnumerable(bValueCollection); var bValueEnumerator = bValueCollection?.GetEnumerator(); if (aValueCollection != null) { if (!options.BitwiseHasFlag(ComparisonOptions.AllowCollectionsToBeOutOfOrder)) { var arrayIndex = 0; // compare elements must be the same order foreach (var collectionItem in aValueCollection) { var hasValue = bValueEnumerator?.MoveNext() ?? false; leftValue = collectionItem; if (hasValue) { rightValue = bValueEnumerator?.Current; if (leftValue == null && rightValue == null) { continue; } if (leftValue == null && rightValue != null) { differences.Add(new Difference(rightValue?.GetType() ?? elementType, propertyName, showName, path, arrayIndex, leftValue, rightValue, typeConverter)); } // check array element for difference if (leftValue != null && !leftValue.GetType().IsValueType&& leftValue.GetType() != typeof(string)) { differences = RecurseProperties(leftValue, rightValue, parent, differences, currentDepth, maxDepth, objectTree, path, options, propertyList); } else if (leftValue != null && leftValue.GetType().IsGenericType&& leftValue.GetType().GetGenericTypeDefinition() == typeof(KeyValuePair <,>)) { // compare keys and values of a KVP var leftKvpKey = GetValueForProperty(leftValue, "Key"); var leftKvpValue = GetValueForProperty(leftValue, "Value"); var rightKvpKey = GetValueForProperty(rightValue, "Key"); var rightKvpValue = GetValueForProperty(rightValue, "Value"); Type leftKeyType = leftKvpKey?.GetType() ?? genericArguments.First(); Type leftValueType = leftKvpValue?.GetType() ?? genericArguments.Skip(1).First(); // compare the key if (leftKvpKey != null && !leftKeyType.IsValueType && leftKeyType != typeof(string)) { differences = RecurseProperties(leftKvpKey, rightKvpKey, leftValue, differences, currentDepth, maxDepth, objectTree, path, options, propertyList); } else { if (!IsMatch(leftKvpKey, rightKvpKey)) { differences.Add(new Difference(leftKeyType, propertyName, path, showName, arrayIndex, leftKvpKey, rightKvpKey, typeConverter)); } } // compare the value if (leftKvpValue != null && !leftValueType.IsValueType && leftValueType != typeof(string)) { differences = RecurseProperties(leftKvpValue, rightKvpValue, leftValue, differences, currentDepth, maxDepth, objectTree, path, options, propertyList); } else { if (!IsMatch(leftValue, rightValue)) { differences.Add(new Difference(leftValueType, propertyName, path, showName, arrayIndex, leftKvpValue, rightKvpValue, typeConverter)); } } } else { if (!IsMatch(leftValue, rightValue)) { differences.Add(new Difference(leftValue?.GetType() ?? elementType, propertyName, showName, path, arrayIndex, leftValue, rightValue, typeConverter)); } } } else { // left has a value in collection, right does not. That's a difference rightValue = null; differences.Add(new Difference(leftValue?.GetType() ?? elementType, propertyName, showName, path, arrayIndex, leftValue, rightValue, typeConverter)); } arrayIndex++; } if (bValueCollectionCount > arrayIndex) { // right side has extra elements var rightSideExtraElements = bValueCollectionCount - arrayIndex; if (bValueEnumerator != null) { for (var i = 0; i < rightSideExtraElements; i++) { var hasValue = bValueEnumerator?.MoveNext() ?? false; if (hasValue) { differences.Add(new Difference(aValueCollection.GetType(), propertyName, showName, path, arrayIndex, null, bValueEnumerator.Current, typeConverter)); arrayIndex++; } } } } } else { // compare elements can be of different order (use the hashcode for this) var leftHashCodeEntryList = new Dictionary <int, CollectionKey>(); // hashcode, value/count var rightHashCodeEntryList = new Dictionary <int, CollectionKey>(); // hashcode, value/count var arrayIndex = 0; foreach (var collectionItem in aValueCollection) { var hashCode = collectionItem.GetHashCode(); if (leftHashCodeEntryList.ContainsKey(hashCode)) { var val = leftHashCodeEntryList[hashCode]; val.Matches++; val.OriginalIndex = arrayIndex; // populate the highest value } else { leftHashCodeEntryList.Add(hashCode, new CollectionKey(arrayIndex, collectionItem, 1)); } arrayIndex++; } arrayIndex = 0; foreach (var collectionItem in bValueCollection) { var hashCode = collectionItem.GetHashCode(); if (rightHashCodeEntryList.ContainsKey(hashCode)) { var val = rightHashCodeEntryList[hashCode]; val.Matches++; val.OriginalIndex = arrayIndex; // populate the highest value } else { rightHashCodeEntryList.Add(hashCode, new CollectionKey(arrayIndex, collectionItem, 1)); } arrayIndex++; } var orderedLeft = leftHashCodeEntryList.OrderBy(x => x.Key); var orderedRight = rightHashCodeEntryList.OrderBy(x => x.Key); // compare the left collection foreach (var item in orderedLeft) { var matchFound = orderedRight.Where(x => x.Key == item.Key).Select(x => x.Value).FirstOrDefault(); if (matchFound == null) { differences.Add(new Difference((leftValue ?? rightValue).GetType(), propertyName, showName, path, item.Value.OriginalIndex, item.Value.Value, null, typeConverter)); } else { var isEqual = CompareForObjectEquality(item.Value.Value.GetExtendedType(DefaultTypeSupportOptions), item.Value.Value, matchFound.Value); if (!isEqual) { differences.Add(new Difference((leftValue ?? rightValue).GetType(), propertyName, showName, path, item.Value.OriginalIndex, item.Value.Value, null, typeConverter)); } else if (matchFound.Matches != item.Value.Matches && item.Value.Matches > matchFound.Matches) { // also compare that the number of instances of the value in a collection are the same differences.Add(new Difference((leftValue ?? rightValue).GetType(), propertyName, showName, path, item.Value.OriginalIndex, item.Value.Value, null, typeConverter)); } } } // compare the right collection foreach (var item in orderedRight) { var matchFound = orderedLeft.Where(x => x.Key == item.Key).Select(x => x.Value).FirstOrDefault(); if (matchFound == null) { differences.Add(new Difference((leftValue ?? rightValue).GetType(), propertyName, showName, path, item.Value.OriginalIndex, null, item.Value.Value, typeConverter)); } else { var isEqual = CompareForObjectEquality(item.Value.Value.GetExtendedType(DefaultTypeSupportOptions), item.Value.Value, matchFound.Value); if (!isEqual) { differences.Add(new Difference((leftValue ?? rightValue).GetType(), propertyName, showName, path, item.Value.OriginalIndex, null, item.Value.Value, typeConverter)); } else if (matchFound.Matches != item.Value.Matches && item.Value.Matches > matchFound.Matches) { // also compare that the number of instances of the value in a collection are the same differences.Add(new Difference((leftValue ?? rightValue).GetType(), propertyName, showName, path, item.Value.OriginalIndex, null, item.Value.Value, typeConverter)); } } } } } } else if (!propertyType.IsValueType && propertyType != typeof(string)) { differences = RecurseProperties(leftValue, rightValue, leftValue, differences, currentDepth, maxDepth, objectTree, path, options, propertyList); } else { if (!IsMatch(leftValue, rightValue)) { differences.Add(new Difference(propertyType, propertyName, showName, path, leftValue, rightValue, typeConverter)); } } return(differences); }
/// <summary> /// Recurse the object's tree /// </summary> /// <param name="left">The left object to compare</param> /// <param name="right">The right object to compare</param> /// <param name="parent">The parent object</param> /// <param name="differences">A list of differences currently found in the tree</param> /// <param name="currentDepth">The current depth of the tree recursion</param> /// <param name="maxDepth">The maximum number of tree children to recurse</param> /// <param name="objectTree">A hash table containing the tree that has already been traversed, to prevent recursion loops</param> /// <param name="options">Specify the comparison options</param> /// <param name="propertyList">A list of property names or full path names to ignore</param> /// <returns></returns> private List <Difference> RecurseProperties(object left, object right, object parent, List <Difference> differences, int currentDepth, int maxDepth, ObjectHashcodeMap objectTree, string path, ComparisonOptions options, List <string> propertyList) { if (GetPropertyInclusionState(null, path, options, propertyList, null) == FilterResult.Exclude) { return(differences); } if (!options.BitwiseHasFlag(ComparisonOptions.AllowCompareDifferentObjects) && left != null && right != null && left?.GetType() != right?.GetType()) { throw new ArgumentException("Objects Left and Right must be of the same type."); } if (left == null && right == null) { return(differences); } if (maxDepth > 0 && currentDepth >= maxDepth) { return(differences); } var typeSupport = new ExtendedType(left != null ? left.GetType() : right.GetType(), DefaultTypeSupportOptions); if (typeSupport.Attributes.Any(x => _ignoreAttributes.Contains(x))) { return(differences); } if (typeSupport.IsDelegate) { return(differences); } if (options.BitwiseHasFlag(ComparisonOptions.AllowEqualsOverride)) { var objectEquality = CompareForObjectEquality(typeSupport, left, right); if (objectEquality) { return(differences); // no differences found, no need to continue } } // increment the current recursion depth currentDepth++; // construct a hashtable of objects we have already inspected (simple recursion loop preventer) // we use this hashcode method as it does not use any custom hashcode handlers the object might implement if (left != null) { if (objectTree.Contains(left)) { return(differences); } objectTree.Add(left); } // get list of properties var properties = new List <ExtendedProperty>(); if (options.BitwiseHasFlag(ComparisonOptions.CompareProperties)) { var pis = left.GetProperties(PropertyOptions.All); foreach (var pi in pis) { if (pi.PropertyInfo.CanWrite == false || pi.PropertyInfo.CanRead == false) { continue; } var atts = pi.PropertyInfo.GetCustomAttributes(true); var canAdd = true; foreach (var att in atts) { var name = att.GetType().Name.ToLower(); if (name.Contains("ignore") || name.Contains("result")) { canAdd = false; break; } } if (canAdd) { properties.Add(pi); } } } // get all fields, except for backed auto-property fields var fields = new List <ExtendedField>(); if (options.BitwiseHasFlag(ComparisonOptions.CompareFields)) { var fis = left.GetFields(FieldOptions.All); foreach (var fi in fis) { if (fi.IsBackingField) { continue; } var atts = fi.FieldInfo.GetCustomAttributes(true); var canAdd = true; foreach (var att in atts) { var name = att.GetType().Name.ToLower(); if (name.Contains("ignore") || name.Contains("result") || name.Contains("nonserialized")) { canAdd = false; break; } } if (canAdd) { fields.Add(fi); } } } var rootPath = path; var localPath = string.Empty; foreach (var property in properties) { localPath = $"{rootPath}.{property.Name}"; if (GetPropertyInclusionState(property.Name, localPath, options, propertyList, property.CustomAttributes) == FilterResult.Exclude) { continue; } object leftValue = null; try { if (left != null) { leftValue = left.GetPropertyValue(property); } } catch (Exception) { // catch any exceptions accessing the property } object rightValue = null; try { if (right != null) { rightValue = right.GetPropertyValue(property); } } catch (Exception) { // catch any exceptions accessing the property } var showName = property.Name; var attr = property.PropertyInfo.GetCustomAttribute <DisplayNameAttribute>(true); if (attr != null) { showName = attr.DisplayName; } differences = GetDifferences(property.Name, showName, property.Type, GetTypeConverter(property), leftValue, rightValue, parent, differences, currentDepth, maxDepth, objectTree, localPath, options, propertyList); } foreach (var field in fields) { localPath = $"{rootPath}.{field.Name}"; if (GetPropertyInclusionState(field.Name, localPath, options, propertyList, field.CustomAttributes) == FilterResult.Exclude) { continue; } object leftValue = null; if (left != null) { leftValue = left.GetFieldValue(field); } object rightValue = null; if (right != null) { rightValue = right.GetFieldValue(field); } var showName = field.Name; var attr = field.FieldInfo.GetCustomAttribute <DisplayNameAttribute>(true); if (attr != null) { showName = attr.DisplayName; } differences = GetDifferences(field.Name, showName, field.Type, GetTypeConverter(field), leftValue, rightValue, parent, differences, currentDepth, maxDepth, objectTree, localPath, options, propertyList); } return(differences); }
/// <summary> /// Compare two objects for value differences /// </summary> /// <param name="left"></param> /// <param name="right"></param> /// <param name="maxDepth"></param> /// <param name="options">Specify the comparison options</param> /// <param name="propertyList">A list of property names or full path names to ignore</param> /// <returns></returns> public List <Difference> ComputeDiff(object left, object right, int maxDepth, ComparisonOptions options, params string[] propertyList) { return(RecurseProperties(left, right, null, new List <Difference>(), 0, maxDepth, new ObjectHashcodeMap(), string.Empty, options, propertyList.ToList())); }
/// <summary> /// Initializes a new instance of the <see cref="PostChangesRequest"/> class. /// </summary> /// <param name="comparisonOptions">Comparison options</param> public PostChangesRequest(ComparisonOptions comparisonOptions) { this.comparisonOptions = comparisonOptions; }
/// <summary> /// Initializes a new instance of the <see cref="ComparisonsRequest"/> class. /// </summary> /// <param name="comparisonOptions">Comparison options</param> public ComparisonsRequest(ComparisonOptions comparisonOptions) { this.comparisonOptions = comparisonOptions; }
internal abstract int GetHashCode(ComparisonOptions options);
/// <summary> /// <para> /// When comparing symbols we need to handle recursion between method type parameters and /// methods. For example, if we have two methods with the signature <c><![CDATA[Foo<T>(T t)]]></c> and we /// try to test for equality we must avoid the situation where we: /// <list type="number"> /// <item>First test if the methods are the same, which will in turn</item> /// <item>test if the method's parameter types are the same, which will in turn</item> /// <item>test if the type parameters are the same, which will in turn</item> /// <item>test if the methods are the same, which causes infinite recursion.</item> /// </list> /// To avoid this we distinguish the cases where we're testing if two type parameters /// actually refer to the same thing, versus type parameters being referenced by parameters. /// For example, if we have: /// <code><![CDATA[ /// Foo<T>(T t) /// Bar<T>(T t) /// ]]></code> /// then clearly the type parameter <c>T</c> in <c><![CDATA[Foo<T>]]></c> is different from the type parameter <c>T</c> /// in <c><![CDATA[Bar<T>]]></c>. When testing these type parameters for equality we *will* test to see /// if they have the same parent. This will end up returning false, and so we will consider /// them different. /// </para> /// <para> /// However, when we are testing if two signatures are the same, if we hit a method type /// parameter then we only need to compare by metadataName. That's because we know we'll /// already have checked if the method and it's parents are the same, so we don't need to /// recurse through them again. /// </para> /// </summary> internal abstract bool Equals(SymbolKey other, ComparisonOptions options);
/// <summary> /// Compares two documents using the indicated comparison options. /// </summary> /// <param name="d1">The first document to compare.</param> /// <param name="d2">The second document to compare.</param> /// <param name="options">The options to use in the comparison.</param> /// <returns>true if the documents are equal, false otherwise.</returns> public static bool DeepEquals(this XDocument d1, XDocument d2, ComparisonOptions options) { if ((d1 ?? d2) == null) return true; if ((d1 == null) || (d2 == null)) return false; // They are not both null, so if either is, then the other isn't return DeepEquals(d1.Root, d2.Root, options); }
/// <summary> /// Compares two nodes using the indicated comparison options. /// </summary> /// <param name="n1">The first node to compare.</param> /// <param name="n2">The second node to compare.</param> /// <param name="options">The options to use in the comparison.</param> /// <returns>true if the nodes are equal, false otherwise.</returns> public static bool DeepEquals(this XNode n1, XNode n2, ComparisonOptions options) { if ((n1 ?? n2) == null) return true; if ((n1 == null) || (n2 == null)) return false; // They are not both null, so if either is, then the other isn't if ((n1 is XElement) && (n2 is XElement)) return DeepEquals((XElement)n1, (XElement)n2, options); else if ((n1 is XComment) && (n2 is XComment)) return DeepEquals((XComment)n1, (XComment)n2, options); else if ((n1 is XText) && (n2 is XText)) return DeepEquals((XText)n1, (XText)n2, options); else if ((n1 is XProcessingInstruction) && (n2 is XProcessingInstruction)) return DeepEquals((XProcessingInstruction)n1, (XProcessingInstruction)n2, options); else if (!(n1.GetType().IsAssignableFrom(n2.GetType()) || n2.GetType().IsAssignableFrom(n1.GetType()))) return false; else throw new NotImplementedException(); }
/// <summary> /// Compare two objects for value differences /// </summary> /// <param name="left">Object A</param> /// <param name="right">Object B</param> /// <param name="options">Specify the comparison options</param> /// <returns></returns> public List <Difference> ComputeDiff(object left, object right, ComparisonOptions options) { return(ComputeDiff(left, right, DefaultMaxDepth, options)); }
/// <summary> /// Compare two objects for value differences /// </summary> /// <param name="left">Object A</param> /// <param name="right">Object B</param> /// <param name="options">Specify the comparison options</param> /// <param name="propertyList">A list of property names or full path names to ignore</param> /// <returns></returns> public List <Difference> ComputeDiff(object left, object right, ComparisonOptions options, params string[] propertyList) { return(ComputeDiff(left, right, DefaultMaxDepth, options, propertyList)); }
/// <summary> /// Compare two objects for value differences /// </summary> /// <typeparam name="T"></typeparam> /// <param name="left"></param> /// <param name="right"></param> /// <param name="options">Specify the comparison options</param> /// <param name="propertyList"></param> /// <returns></returns> public List <Difference> ComputeDiff <T>(T left, T right, ComparisonOptions options, params Expression <Func <T, object> >[] propertyList) { return(ComputeDiff(left, right, DefaultMaxDepth, options, propertyList)); }
private static bool ShouldCompareReferences(PropertyInfo property, string propertyNamespace, ComparisonOptions settings) { return(settings.PropertiesToCompareByReference.NullSafe().Any(r => propertyNamespace + property.Name == r)); }
internal override bool Equals(MethodTypeParameterSymbol other, ComparisonOptions options) { return(Equals(options.IgnoreCase, other._metadataName, _metadataName) && (options.CompareMethodTypeParametersByName || other._containerKey.Equals(_containerKey, options))); }
/// <summary> /// Compare two objects for value differences /// </summary> /// <param name="left">Object A</param> /// <param name="right">Object B</param> /// <param name="comparisonOptions">Specify the comparison options</param> /// <param name="diffOptions">Specify custom diff options</param> /// <param name="propertiesToExcludeOrInclude">A list of property names or full path names to include/exclude. Default is <seealso cref="ComparisonOptions.ExcludeList"/>. Specify <seealso cref="ComparisonOptions.ExcludeList"/> to exclude the specified properties from the Diff or <seealso cref="ComparisonOptions.IncludeList"/> to only Diff properties contained in the list.</param> /// <returns></returns> public static ICollection <Difference> Diff(this object left, object right, ComparisonOptions comparisonOptions, DiffOptions diffOptions, params string[] propertiesToExcludeOrInclude) { return(Diff(left, right, DiffProvider.DefaultMaxDepth, comparisonOptions, diffOptions, propertiesToExcludeOrInclude)); }
internal override bool Equals(FieldSymbolKey other, ComparisonOptions options) { return (Equals(options.IgnoreCase, other._metadataName, _metadataName) && other._containerKey.Equals(_containerKey, options)); }
private static SymbolKeyComparer EnsureInitialized(ref SymbolKeyComparer location, ComparisonOptions options) { // This doesn't need to be interlocked since comparers store no state return(location ?? (location = new SymbolKeyComparer(options))); }
internal override bool Equals(AssemblySymbolKey other, ComparisonOptions options) { // isCaseSensitive doesn't apply here as AssemblyIdentity is always case // insensitive. return(options.IgnoreAssemblyKey || other.assemblyName == this.assemblyName); }
internal override bool Equals(NonDeclarationSymbolKey <TSymbol> other, ComparisonOptions options) { throw new NotImplementedException(); }
internal override int GetHashCode(ComparisonOptions options) { // isCaseSensitive doesn't apply here as AssemblyIdentity is always case // insensitive. return(options.IgnoreAssemblyKey ? 1 : this.assemblyName.GetHashCode()); }
internal override bool Equals(TypeParameterSymbolKey other, ComparisonOptions options) { return Equals(options.IgnoreCase, other.metadataName, this.metadataName) && other.containerKey.Equals(this.containerKey, options); }
internal override bool Equals(SymbolKey other, ComparisonOptions options) { return(ReferenceEquals(this, other)); }
/// <summary> /// Compares two elements using the indicated comparison options. /// </summary> /// <param name="e1">The first element to compare.</param> /// <param name="e2">The second element to compare.</param> /// <param name="options">The options to use in the comparison.</param> /// <returns>true if the elements are equal, false otherwise.</returns> public static bool DeepEquals(this XElement e1, XElement e2, ComparisonOptions options) { if ((e1 ?? e2) == null) return true; if ((e1 == null) || (e2 == null)) return false; // They are not both null, so if either is, then the other isn't // Compare the name if (!CompareNames(e1.Name, e2.Name, options)) return false; // Performance tweak: compare attributes first, because they will often be faster to find a difference return AttributesEqual(e1, e2, options) && ContentsEqual(e1, e2, options); }
internal override int GetHashCode(ComparisonOptions options) { return(RuntimeHelpers.GetHashCode(this)); }
/// <summary> /// Compares two attributes using the indicated comparison options. /// </summary> /// <param name="a1">The first attribute to compare.</param> /// <param name="a2">The second attribute to compare.</param> /// <param name="options">The options to use in the comparison.</param> /// <returns>true if the attributes are equal, false otherwise.</returns> public static bool DeepEquals(this XAttribute a1, XAttribute a2, ComparisonOptions options) { if ((a1 ?? a2) == null) return true; if ((a1 == null) || (a2 == null)) return false; // They are not both null, so if either is, then the other isn't // Compare the name if (!CompareNames(a1.Name, a2.Name, options)) return false; return a1.Value == a2.Value; }
internal override int GetHashCode(ComparisonOptions options) { return(Hash.Combine( GetHashCode(options.IgnoreCase, this.metadataName), this.containerKey.GetHashCode(options))); }
/// <summary> /// Checks if two elements have equal attributes. /// </summary> /// <param name="e1">The first element to compare.</param> /// <param name="e2">The second element to compare.</param> /// <param name="options">The options to use in the comparison.</param> /// <returns>true if the element attributes are equal, false otherwise.</returns> private static bool AttributesEqual(XElement e1, XElement e2, ComparisonOptions options) { // They must both have or not have attributes, and if they don't we're good and can exit early if (e1.HasAttributes != e2.HasAttributes) return false; if (!e1.HasAttributes) return true; var attributes1 = e1.Attributes(); var attributes2 = e2.Attributes(); // We will ignore attribute ordering if ((options & ComparisonOptions.AttributeOrdering) != ComparisonOptions.AttributeOrdering) { attributes1 = attributes1.OrderBy(x => x.Name.Namespace.NamespaceName + x.Name.LocalName); attributes2 = attributes2.OrderBy(x => x.Name.Namespace.NamespaceName + x.Name.LocalName); } var enum1 = attributes1.GetEnumerator(); var enum2 = attributes2.GetEnumerator(); var next1 = enum1.MoveNext(); var next2 = enum2.MoveNext(); while (next1 && next2) { if (enum1.Current.IsNamespaceDeclaration != enum2.Current.IsNamespaceDeclaration) return false; if (!enum1.Current.IsNamespaceDeclaration || ((options & ComparisonOptions.NamespacePrefix) == ComparisonOptions.NamespacePrefix)) if (!DeepEquals(enum1.Current, enum2.Current, options)) return false; next1 = enum1.MoveNext(); next2 = enum2.MoveNext(); } // They have the same number of elements if these are equal return next1 == next2; }
/// <summary> /// Compare two objects for value differences /// </summary> /// <typeparam name="T"></typeparam> /// <param name="left">Object A</param> /// <param name="right">Object B</param> /// <param name="comparisonOptions">Specify the comparison options</param> /// <param name="diffOptions">Specify custom diff options</param> /// <param name="propertiesToExcludeOrInclude">A list of property names or full path names to include/exclude. Default is <seealso cref="ComparisonOptions.ExcludeList"/>. Specify <seealso cref="ComparisonOptions.ExcludeList"/> to exclude the specified properties from the Diff or <seealso cref="ComparisonOptions.IncludeList"/> to only Diff properties contained in the list.</param> /// <returns></returns> public static ICollection <Difference> Diff <T>(this T left, T right, ComparisonOptions comparisonOptions, DiffOptions diffOptions, params Expression <Func <T, object> >[] propertiesToExcludeOrInclude) { return(Diff(left, right, DiffProvider.DefaultMaxDepth, comparisonOptions, diffOptions, propertiesToExcludeOrInclude)); }
/// <summary> /// Checks if two elements have equal content. /// </summary> /// <param name="e1">The first element to compare.</param> /// <param name="e2">The second element to compare.</param> /// <param name="options">The options to use in the comparison.</param> /// <returns>true if the element contents are equal, false otherwise.</returns> private static bool ContentsEqual(XElement e1, XElement e2, ComparisonOptions options) { if (e1.Value != e2.Value) return false; if ((e1.IsEmpty != e2.IsEmpty) && ((options & ComparisonOptions.EmptyTagStyle) == ComparisonOptions.EmptyTagStyle)) return false; if (e1.IsEmpty && e2.IsEmpty) return true; var nodes1 = e1.Nodes(); var nodes2 = e2.Nodes(); // Exclude comments and notations if ((options & ComparisonOptions.CommentsAndNotations) != ComparisonOptions.CommentsAndNotations) { nodes1 = nodes1.Where(x => x.NodeType != XmlNodeType.Comment && x.NodeType != XmlNodeType.Notation); nodes2 = nodes2.Where(x => x.NodeType != XmlNodeType.Comment && x.NodeType != XmlNodeType.Notation); } // Order the nodes if required if ((options & ComparisonOptions.ElementOrdering) != ComparisonOptions.ElementOrdering) { nodes1 = nodes1.OrderBy(x => x.ToString()); nodes2 = nodes2.OrderBy(x => x.ToString()); } var enum1 = nodes1.GetEnumerator(); var enum2 = nodes2.GetEnumerator(); var next1 = enum1.MoveNext(); var next2 = enum2.MoveNext(); while (next1 && next2) { if (!DeepEquals(enum1.Current, enum2.Current, options)) return false; next1 = enum1.MoveNext(); next2 = enum2.MoveNext(); } // They have the same number of elements if these are equal return next1 == next2; }
/// <summary> /// Compare two objects for value differences /// </summary> /// <param name="left">Object A</param> /// <param name="right">Object B</param> /// <param name="maxDepth">Maximum recursion depth</param> /// <param name="comparisonOptions">Specify the comparison options</param> /// <param name="diffOptions">Specify custom diff options</param> /// <param name="propertiesToExcludeOrInclude">A list of property names or full path names to include/exclude. Default is <seealso cref="ComparisonOptions.ExcludeList"/>. Specify <seealso cref="ComparisonOptions.ExcludeList"/> to exclude the specified properties from the Diff or <seealso cref="ComparisonOptions.IncludeList"/> to only Diff properties contained in the list.</param> /// <returns></returns> public static ICollection <Difference> Diff(this object left, object right, int maxDepth, ComparisonOptions comparisonOptions, DiffOptions diffOptions, params string[] propertiesToExcludeOrInclude) { var diffProvider = new DiffProvider(); return(diffProvider.ComputeDiff(left, right, maxDepth, comparisonOptions, diffOptions, propertiesToExcludeOrInclude)); }
/// <summary> /// Compares two processing instructions using the indicated comparison options. /// </summary> /// <param name="p1">The first processing instruction to compare.</param> /// <param name="p2">The second processing instruction to compare.</param> /// <param name="options">The options to use in the comparison.</param> /// <returns>true if the processing instructions are equal, false otherwise.</returns> public static bool DeepEquals(this XProcessingInstruction p1, XProcessingInstruction p2, ComparisonOptions options) { if ((p1 ?? p2) == null) return true; if ((p1 == null) || (p2 == null)) return false; // They are not both null, so if either is, then the other isn't return ((p1.Target == p2.Target) && (p1.Data == p1.Data)); }
/// <summary> /// Compare two objects for value differences /// </summary> /// <typeparam name="T"></typeparam> /// <param name="left">Object A</param> /// <param name="right">Object B</param> /// <param name="maxDepth">Maximum recursion depth</param> /// <param name="comparisonOptions">Specify the comparison options</param> /// <param name="diffOptions">Specify custom diff options</param> /// <param name="propertiesToExcludeOrInclude">A list of property names or full path names to include/exclude. Default is <seealso cref="ComparisonOptions.ExcludeList"/>. Specify <seealso cref="ComparisonOptions.ExcludeList"/> to exclude the specified properties from the Diff or <seealso cref="ComparisonOptions.IncludeList"/> to only Diff properties contained in the list.</param> /// <returns></returns> public static ICollection <Difference> Diff <T>(this T left, T right, int maxDepth, ComparisonOptions comparisonOptions, DiffOptions diffOptions, params Expression <Func <T, object> >[] propertiesToExcludeOrInclude) { var diffProvider = new DiffProvider(); return(diffProvider.ComputeDiff(left, right, maxDepth, comparisonOptions, diffOptions, propertiesToExcludeOrInclude)); }
internal override int GetHashCode(ComparisonOptions options) { return RuntimeHelpers.GetHashCode(this); }
// ReSharper restore CompareNonConstrainedGenericWithNull private static FilteredProperties FilterProperties(IEnumerable <PropertyInfo> properties, string propertyNamespace, ComparisonOptions settings) { var namespaceWithoutIndexes = _collectionIndexPattern.Replace(propertyNamespace, "[]"); if (settings.ComparisonType == ComparisonType.Inclusive) { var toIgnore = settings.PropertiesToIgnore.NullSafe().ToList(); var splitProperties = properties.ToLookup(p => toIgnore.Contains(namespaceWithoutIndexes + p.Name)); return(new FilteredProperties { PropertiesToCompare = splitProperties[false].NullSafe().ToList(), IgnoredPropertyNames = splitProperties[true].NullSafe().Select(p => propertyNamespace + p.Name).ToList() }); } else { var toInclude = settings.PropertiesToCompare.NullSafe().ToList(); var splitProperties = properties.ToLookup(p => toInclude.Any(i => i.NullSafe().StartsWith(namespaceWithoutIndexes + p.Name))); return(new FilteredProperties { PropertiesToCompare = splitProperties[true].NullSafe().ToList(), IgnoredPropertyNames = splitProperties[false].NullSafe().Select(p => propertyNamespace + p.Name).ToList() }); } }