public static bool IsUnorderedEqualTo <TElement>(
            this IEnumerable <TElement> item1,
            IEnumerable <TElement> item2,
            IEqualityComparer <TElement> elementComparer = null)
        {
            if (ReferenceEquals(item1, item2))
            {
                return(true);
            }

            if (ReferenceEquals(item1, null) || ReferenceEquals(item2, null))
            {
                return(false);
            }

            var equalityComparerToUse = EqualityComparerHelper.GetEqualityComparerToUse(elementComparer);

            // ReSharper disable once PossibleMultipleEnumeration
            var item1AsList = item1.ToList();

            // ReSharper disable once PossibleMultipleEnumeration
            var item2AsList = item2.ToList();

            if (item1AsList.Count != item2AsList.Count)
            {
                return(false);
            }

            foreach (var item1Element in item1AsList)
            {
                var elementFound = false;

                for (var x = 0; x < item2AsList.Count; x++)
                {
                    var item2Element = item2AsList[x];

                    if (equalityComparerToUse.Equals(item1Element, item2Element))
                    {
                        item2AsList.RemoveAt(x);

                        elementFound = true;

                        break;
                    }
                }

                if (!elementFound)
                {
                    return(false);
                }
            }

            return(true);
        }
        /// <summary>
        /// Compares objects for equality.
        /// </summary>
        /// <typeparam name="T">The type of objects to compare.</typeparam>
        /// <param name="item1">The first object to compare.</param>
        /// <param name="item2">The second object to compare.</param>
        /// <param name="comparer">Optional equality comparer to use to compare the objects.  Default is to call <see cref="EqualityComparerHelper.GetEqualityComparerToUse{T}(IEqualityComparer{T})"/>.</param>
        /// <returns>
        /// - true if the two objects are equal
        /// - otherwise, false.
        /// </returns>
        public static bool IsEqualTo <T>(
            this T item1,
            T item2,
            IEqualityComparer <T> comparer = null)
        {
            if (ReferenceEquals(item1, item2))
            {
                return(true);
            }

            if (ReferenceEquals(item1, null) || ReferenceEquals(item2, null))
            {
                return(false);
            }

            var equalityComparerToUse = EqualityComparerHelper.GetEqualityComparerToUse(comparer);

            var result = equalityComparerToUse.Equals(item1, item2);

            return(result);
        }
        /// <summary>
        /// Compares two dictionaries for equality.
        /// </summary>
        /// <typeparam name="TElement">The type of the elements of the input sequences.</typeparam>
        /// <param name="item1">An <see cref="IEnumerable{T}"/> to compare to <paramref name="item2"/>.</param>
        /// <param name="item2">An <see cref="IEnumerable{T}"/> to compare to the first sequence.</param>
        /// <param name="elementComparer">Optional equality comparer to use to compare the elements.  Default is to call <see cref="EqualityComparerHelper.GetEqualityComparerToUse{T}(IEqualityComparer{T})"/>.</param>
        /// <returns>
        /// - true if the two source sequences are null.
        /// - false if one or the other is null.
        /// - true if the two sequences are of equal length and their corresponding elements are equal according to <paramref name="elementComparer"/>.
        /// - otherwise, false.
        /// </returns>
        public static bool IsSequenceEqualTo <TElement>(
            this IEnumerable <TElement> item1,
            IEnumerable <TElement> item2,
            IEqualityComparer <TElement> elementComparer = null)
        {
            if (ReferenceEquals(item1, item2))
            {
                return(true);
            }

            if (ReferenceEquals(item1, null) || ReferenceEquals(item2, null))
            {
                return(false);
            }

            var equalityComparerToUse = EqualityComparerHelper.GetEqualityComparerToUse(elementComparer);

            var result = item1.SequenceEqual(item2, equalityComparerToUse);

            return(result);
        }
        /// <summary>
        /// Compares two dictionaries for equality.
        /// </summary>
        /// <typeparam name="TKey">The type of keys in the dictionaries.</typeparam>
        /// <typeparam name="TValue">The type of values in the dictionaries.</typeparam>
        /// <param name="item1">The first <see cref="IReadOnlyDictionary{TKey, TValue}"/> to compare.</param>
        /// <param name="item2">The second <see cref="IReadOnlyDictionary{TKey, TValue}"/> to compare.</param>
        /// <param name="valueComparer">Optional equality comparer to use to compare values.  Default is to call <see cref="EqualityComparerHelper.GetEqualityComparerToUse{T}(IEqualityComparer{T})"/>.</param>
        /// <returns>
        /// - true if the two source dictionaries are null.
        /// - false if one or the other is null.
        /// - false if the dictionaries are of different length.
        /// - true if the two dictionaries are of equal length and their values are equal for the same keys.
        /// - otherwise, false.
        /// </returns>
        public static bool IsDictionaryEqualTo <TKey, TValue>(
            this IDictionary <TKey, TValue> item1,
            IDictionary <TKey, TValue> item2,
            IEqualityComparer <TValue> valueComparer = null)
        {
            if (ReferenceEquals(item1, item2))
            {
                return(true);
            }

            if (ReferenceEquals(item1, null) || ReferenceEquals(item2, null))
            {
                return(false);
            }

            if (item1.Keys.Count != item2.Keys.Count)
            {
                return(false);
            }

            IEqualityComparer <TValue> valueEqualityComparerToUse = null;

            foreach (var key in item1.Keys)
            {
                // We rely on the IEqualityComparer<T> contained within the dictionaries to compare keys.
                // As such, two dictionaries that use a default equality comparer that just compares
                // object references, will never be equal.  For example, two dictionaries that are keyed on
                // a List<string> will never be equal, regardless of whether
                // item1.Keys.IsUnorderedEqualTo(item2.Keys) is true or false unless the keys are the same
                // object reference.
                // We took this approach because we wanted to respect the dictionary's contract for comparing
                // keys.  A dictionary that is keyed on a type that can only be compared by object reference
                // is rare and it's own smell.  In the example above, two dictionaries may well "look" like
                // they are equal, but if their List<string> keys are different references, then the dictionaries
                // cannot be substituted.  Looking-up values using the keys of one dictionary with the other
                // dictionary would fail.
                //
                // Note that two dictionaries keyed on DateTime, having the keys with the same number of Ticks
                // but with different DateTime.Kind, will be considered equal because here we are using .NET's
                // default equality comparer and not our own.  There is no way to use our own while solving for
                // the comments above (the reason why we use the comparer embedded in the dictionary in the first place).
                if (!item2.ContainsKey(key))
                {
                    return(false);
                }

                var item1Value = item1[key];
                var item2Value = item2[key];

                if (valueEqualityComparerToUse == null)
                {
                    valueEqualityComparerToUse = EqualityComparerHelper.GetEqualityComparerToUse(valueComparer);
                }

                if (!valueEqualityComparerToUse.Equals(item1Value, item2Value))
                {
                    return(false);
                }
            }

            // As mentioned above, we rely on the IEqualityComparer<T> contained within the dictionaries
            // to compare keys.  As such, we need to check that every item1 key is contained within item2
            // AND vice-versa and hence the need for the following second loop.  To illustrate the need,
            // take two dictionaries that are keyed on string where item1 was constructed using
            // StringComparer.InvariantCulture and item1 was constructed using
            // StringComparer.InvariantCultureIgnoreCase.  If every item1 key is upper-case and every item2
            // key is lower-case, but otherwise the keys match, then the loop above would determine that
            // the dictionaries are equal whereas the loop below would return false and as such these
            // dictionaries are not substitutable as inputs to some consuming body of code.
            foreach (var key in item2.Keys)
            {
                if (!item1.ContainsKey(key))
                {
                    return(false);
                }

                var item1Value = item1[key];
                var item2Value = item2[key];

                if (valueEqualityComparerToUse == null)
                {
                    valueEqualityComparerToUse = EqualityComparerHelper.GetEqualityComparerToUse(valueComparer);
                }

                if (!valueEqualityComparerToUse.Equals(item1Value, item2Value))
                {
                    return(false);
                }
            }

            return(true);
        }