/// <summary>
        /// Determines whether two lists of <see cref="MemberBinding"/> are similar.
        /// </summary>
        /// <param name="source">The source list.</param>
        /// <param name="target">The target list.</param>
        /// <returns>A value indicating whether the individual bindings are similar.</returns>
        public static bool MemberBindingsAreSimilar(
            IList <MemberBinding> source,
            IList <MemberBinding> target)
        {
            if (source.Count() != target.Count())
            {
                return(false);
            }

            var similar = true;

            for (var idx = 0; idx < source.Count() && similar; idx += 1)
            {
                if (source[idx].BindingType != target[idx].BindingType)
                {
                    return(false);
                }

                if (source[idx] is MemberAssignment assign)
                {
                    var targetAssign = target[idx] as MemberAssignment;
                    similar = assign.Member.MemberType == targetAssign.Member.MemberType &&
                              TypesAreSimilar(assign.Member.DeclaringType, targetAssign.Member.DeclaringType) &&
                              IsPartOf(assign.Expression, targetAssign.Expression);
                }

                if (source[idx] is MemberMemberBinding memberMemberBinding)
                {
                    var targetMemberBinding = target[idx] as MemberMemberBinding;
                    similar = memberMemberBinding.Member.MemberType == targetMemberBinding.Member.MemberType &&
                              TypesAreSimilar(memberMemberBinding.Member.DeclaringType, targetMemberBinding.Member.DeclaringType) &&
                              MemberBindingsAreSimilar(memberMemberBinding.Bindings, targetMemberBinding.Bindings);
                }

                if (source[idx] is MemberListBinding memberListBinding)
                {
                    var targetListBinding = target[idx] as MemberListBinding;
                    similar = memberListBinding.Member.MemberType == targetListBinding.Member.MemberType &&
                              TypesAreSimilar(memberListBinding.Member.DeclaringType, targetListBinding.Member.DeclaringType) &&
                              ExpressionEquivalency.NonGenericEnumerablesAreEquivalent(
                        memberListBinding.Initializers, targetListBinding.Initializers);
                }
            }

            return(similar);
        }
 /// <summary>
 /// Ensures that two <see cref="MemberBinding"/> instances are equivalent.
 /// </summary>
 /// <param name="source">The source <see cref="MemberBinding"/>.</param>
 /// <param name="target">The target <see cref="MemberBinding"/>.</param>
 /// <returns>A value that indicates whether the bindings are equivalent.</returns>
 public bool MemberBindingsAreEquivalent(MemberBinding source, MemberBinding target) =>
 ExpressionEquivalency.MemberBindingsAreEquivalent(source, target);
 /// <summary>
 /// Ensures two dictionaries are equivalent.
 /// </summary>
 /// <param name="source">The source <see cref="IDictionary"/>.</param>
 /// <param name="target">The target <see cref="IDictionary"/>.</param>
 /// <returns>A value indicating whether the dictionaries are equivalent.</returns>
 public bool DictionariesAreEquivalent(IDictionary source, IDictionary target) =>
 ExpressionEquivalency.DictionariesAreEquivalent(source, target);
 /// <summary>
 /// Determine if a <see cref="Type"/> is equivalent to another type.
 /// </summary>
 /// <remarks>
 /// Handles anonymous types converted to dynamic dictionary.
 /// </remarks>
 /// <param name="source">The source <see cref="Type"/>.</param>
 /// <param name="target">The target <see cref="Type"/>.</param>
 /// <returns>A value indicating whether the types are equivalent.</returns>
 public bool TypesAreEquivalent(Type source, Type target) =>
 ExpressionEquivalency.TypesAreEquivalent(source, target);
 /// <summary>
 /// Attempts to compare values in various ways.
 /// </summary>
 /// <remarks>
 /// <para>If one side is <c>null</c> and other is not <c>null</c>, returns <c>false</c>. If the objects are the same reference,
 /// returns <c>true</c>. If the type implements <see cref="IEquatable{T}"/> then the result of <see cref="IEquatable{T}.Equals(T)"/>
 /// is returned. If the type implements <see cref="IComparable"/> then the result is <c>true</c> if
 /// <see cref="IComparable.CompareTo(object)"/> is <c>0</c>. Otherwise, the result of <see cref="object.Equals(object)"/> from
 /// the source to the target is returned.</para>
 /// <para>Exceptions are compared by the `Message` property. The comparison is also recursive: if a type is found that has an
 /// existing comparison method, the method is called for further validation.</para>
 /// </remarks>
 /// <param name="source">The source value.</param>
 /// <param name="target">The target value.</param>
 /// <returns>A flag indicating equivalency.</returns>
 public bool ValuesAreEquivalent(object source, object target) =>
 ExpressionEquivalency.ValuesAreEquivalent(source, target);
 /// <summary>
 /// Comparison of multiple expressions. Equivalent
 /// only when all elements match, in order, and
 /// pass the equivalent test.
 /// </summary>
 /// <param name="source">The source expressions.</param>
 /// <param name="target">The target expressions.</param>
 /// <returns>A flag indicating whether the two sets of
 /// expressions are equivalent.</returns>
 public bool AreEquivalent(
     IEnumerable <Expression> source, IEnumerable <Expression> target) =>
 ExpressionEquivalency.AreEquivalent(source, target);
 /// <summary>
 /// Entry for equivalency comparisons. Will cast to
 /// known types and compare.
 /// </summary>
 /// <typeparam name="T">The <see cref="Type"/> of the entity.</typeparam>
 /// <param name="source">The source <see cref="IQueryable{T}"/>.</param>
 /// <param name="target">The target <see cref="IQueryable{T}"/> to compare to.</param>
 /// <returns>A flag indicating whether the source and target are equivalent.</returns>
 public bool AreEquivalent <T>(IQueryable <T> source, IQueryable <T> target) =>
 ExpressionEquivalency.AreEquivalent(source?.Expression, target?.Expression);
 /// <summary>
 /// Entry for equivalency comparisons. Will cast to
 /// known types and compare.
 /// </summary>
 /// <param name="source">The source <see cref="Expression"/>.</param>
 /// <param name="target">The target <see cref="Expression"/> to compare to.</param>
 /// <returns>A flag indicating whether the source and target are equivalent.</returns>
 public bool AreEquivalent(Expression source, Expression target) =>
 ExpressionEquivalency.AreEquivalent(source, target);
 /// <summary>
 /// Comparison matrix for types and nulls.
 /// </summary>
 /// <param name="source">The source to compare.</param>
 /// <param name="other">The target to compare to.</param>
 /// <returns>A flag indicating whether the types are
 /// equal and the values are both not null.</returns>
 public bool NullAndTypeCheck(Expression source, Expression other) =>
 ExpressionEquivalency.NullAndTypeCheck(source, other);
 /// <summary>
 /// Ensures two enumerables are same length an each value is equivalent.
 /// </summary>
 /// <param name="srcEnumerable">The source <see cref="IEnumerable"/>.</param>
 /// <param name="tgtEnumerable">The target <see cref="IEnumerable"/>.</param>
 /// <returns>A flag indicating whether the two are equivalent.</returns>
 public bool NonGenericEnumerablesAreEquivalent(IEnumerable srcEnumerable, IEnumerable tgtEnumerable) =>
 ExpressionEquivalency.NonGenericEnumerablesAreEquivalent(srcEnumerable, tgtEnumerable);