/// <summary>
        /// Compares the specified object graphs. It is called by <see cref="ObjectGraphComparer"/>.
        /// </summary>
        /// <param name="left">The left.</param>
        /// <param name="right">The right.</param>
        /// <param name="comparer">
        /// The calling comparer to compare object sub-graphs, which the given strategy does
        /// not work with and perform other interactions.
        /// </param>
        /// <returns>
        /// <c>true</c> if the specified nodes are equal; otherwise, <c>false</c>.
        /// </returns>
        internal bool Compare(GraphNode left, GraphNode right, ObjectGraphComparer comparer)
        {
            Debug.Assert(left != null);
            Debug.Assert(right != null);
            Debug.Assert(comparer != null);

            EnterCompare(comparer);

            try
            {
                var mismatches = Compare(left, right);
                if (mismatches != null)
                {
                    ComparisonResult &= !mismatches.Any();
                    foreach (var m in mismatches)
                    {
                        Comparer.AddMismatch(m);
                    }
                }

                return(ComparisonResult);
            }
            finally
            {
                ExitCompare();
            }
        }
 public ComparerResultTuple(ObjectGraphComparer comparer)
 {
     Comparer         = comparer;
     ComparisonResult = true;
 }
 private void EnterCompare(ObjectGraphComparer comparer)
 {
     comparisons.Push(new ComparerResultTuple(comparer));
 }
        /// <summary>
        /// Performs and unordered comparison of the given object graph collections.
        /// </summary>
        /// <param name="leftNodes">The left nodes.</param>
        /// <param name="rightNodes">The right nodes.</param>
        private bool CompareObjectGraphs(IEnumerable <GraphNode> leftNodes, IEnumerable <GraphNode> rightNodes)
        {
            var left  = leftNodes.ToList();
            var right = rightNodes.ToList();

            if (left.Count == 1 && right.Count == 1)
            {
                return(CompareObjectGraphs(left.First(), right.First()));
            }

            var mismatchesCount = m_mismatches.Count;

            // One of the groups has more than 1 element, since we are
            // doing unordered comparison by default, we need to
            // go through elements in both groups and find matches
            var leftIndex = 0;

            while (leftIndex < left.Count)
            {
                var found = false;
                for (int rightIndex = 0; rightIndex < right.Count; rightIndex++)
                {
                    if (m_probing)
                    {
                        // If we are already in the probing mode, there is no need to
                        // create a yet new comparer
                        found = CompareObjectGraphs(left[leftIndex], right[rightIndex]);
                        if (!found)
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        var probingComparer = new ObjectGraphComparer(m_visited);
                        found = probingComparer.CompareObjectGraphs(left[leftIndex], right[rightIndex]);
                        // If nodes match, need to remember visited sub-nodes
                        if (found)
                        {
                            m_visited.UnionWith(probingComparer.m_visited);
                        }
                    }

                    if (found)
                    {
                        left.RemoveAt(leftIndex);
                        right.RemoveAt(rightIndex);
                        break;
                    }
                }

                if (!found)
                {
                    leftIndex++;
                }
            }

            // Now left and right contain elements without a match
            // Go through them and get mismatches...
            while (left.Any() && right.Any())
            {
                // ...but, if we are just probing for equality of nodes, we already
                // know the answer
                if (m_probing)
                {
                    return(false);
                }

                CompareObjectGraphs(left.First(), right.First());
                left.RemoveAt(0);
                right.RemoveAt(0);
            }

            if (left.Any() || right.Any())
            {
                // If we are just probing for equality of nodes, we already
                // know the answer
                if (m_probing)
                {
                    return(false);
                }

                AddMissingNodeMismatches(left, true);
                AddMissingNodeMismatches(right, false);
            }

            return(m_mismatches.Count == mismatchesCount);
        }