/// <summary>
        /// Gets the members (fields, properties, constructors, methods, and events) of the specified type,
        /// with various options to control the scope of members included and optionally order the members.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="memberRelationships">OPTIONAL value that scopes the search for members based on their relationship to <paramref name="type"/>.  DEFAULT is to include the members declared in or inherited by the specified type.</param>
        /// <param name="memberOwners">OPTIONAL value that scopes the search for members based on who owns the member.  DEFAULT is to include members owned by an object or owned by the type itself.</param>
        /// <param name="memberAccessModifiers">OPTIONAL value that scopes the search for members based on access modifiers.  DEFAULT is to include members having any supported access modifier.</param>
        /// <param name="memberKinds">OPTIONAL value that scopes the search for members based on the kind of member.  DEFAULT is to include all kinds of members.</param>
        /// <param name="memberMutability">OPTIONAL value that scopes the search for members based on mutability.  DEFAULT is to include members where mutability is not applicable and where applicable, include members with any kind of mutability.</param>
        /// <param name="memberAttributes">OPTIONAL value that scopes the search for members based on the presence or absence of certain attributes on those members.  DEFAULT is to include members that are not compiler generated.</param>
        /// <param name="orderMembersBy">OPTIONAL value that specifies how to the members.  DEFAULT is return the members in no particular order.</param>
        /// <returns>
        /// The members in the specified order.
        /// </returns>
        /// <exception cref="ArgumentNullException"><paramref name="type"/> is null.</exception>
        public static IReadOnlyList <MemberInfo> GetMembersFiltered(
            this Type type,
            MemberRelationships memberRelationships = MemberRelationships.DeclaredOrInherited,
            MemberOwners memberOwners = MemberOwners.All,
            MemberAccessModifiers memberAccessModifiers = MemberAccessModifiers.All,
            MemberKinds memberKinds           = MemberKinds.All,
            MemberMutability memberMutability = MemberMutability.All,
            MemberAttributes memberAttributes = MemberAttributes.NotCompilerGenerated,
            OrderMembersBy orderMembersBy     = OrderMembersBy.None)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            var result = type
                         .GetMembersHavingRelationshipsAndOwners(memberRelationships, memberOwners)
                         .FilterMembersHavingKinds(memberKinds)
                         .FilterMembersHavingAccessModifiers(memberAccessModifiers)
                         .FilterMembersHavingMutability(memberMutability)
                         .FilterMembersHavingAttributes(memberAttributes)
                         .OrderMembers(type, orderMembersBy);

            return(result);
        }
        private static IReadOnlyList <MemberInfo> OrderMembers(
            this IReadOnlyList <MemberInfo> members,
            Type type,
            OrderMembersBy orderMembersBy)
        {
            IReadOnlyList <MemberInfo> result;

            if (orderMembersBy == OrderMembersBy.None)
            {
                result = members;
            }
            else if (orderMembersBy == OrderMembersBy.MemberName)
            {
                result = members.OrderBy(_ => _.Name).ToList();
            }
            else if ((orderMembersBy == OrderMembersBy.DeclaringTypeDerivationPath) || (orderMembersBy == OrderMembersBy.DeclaringTypeDerivationPathThenByMemberName))
            {
                var typeToIndexMap = new Type[0]
                                     .Concat(new[] { type })
                                     .Concat(type.GetInheritancePath())
                                     .Reverse()
                                     .Select((t, i) => new { Type = t, Index = i })
                                     .ToDictionary(_ => _.Type, _ => _.Index);

                var orderedMembers = members
                                     .OrderBy(_ =>
                {
                    if (_.DeclaringType == null)
                    {
                        throw new NotSupportedException(Invariant($"Found a {_.GetType().ToStringReadable()} member named {_.Name} whose {nameof(MemberInfo.DeclaringType)} is null, which is not supported.  Member's {nameof(object.ToString)} value is: {_.ToString()}"));
                    }

                    // if member's declaring type is not in inheritance path, then
                    // ordered before all other members.
                    var index = typeToIndexMap.ContainsKey(_.DeclaringType)
                            ? typeToIndexMap[_.DeclaringType]
                            : -1;

                    return(index);
                });

                if (orderMembersBy == OrderMembersBy.DeclaringTypeDerivationPathThenByMemberName)
                {
                    orderedMembers = orderedMembers.ThenBy(_ => _.Name);
                }

                result = orderedMembers.ToList();
            }
            else
            {
                throw new NotSupportedException(Invariant($"This {nameof(OrderMembersBy)} is not supported: {orderMembersBy}."));
            }

            return(result);
        }
        /// <summary>
        /// Gets the methods of the specified type,
        /// with various options to control the scope of methods included and optionally order the methods.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="memberRelationships">OPTIONAL value that scopes the search for members based on their relationship to <paramref name="type"/>.  DEFAULT is to include the members declared in or inherited by the specified type.</param>
        /// <param name="memberOwners">OPTIONAL value that scopes the search for members based on who owns the member.  DEFAULT is to include members owned by an object or owned by the type itself.</param>
        /// <param name="memberAccessModifiers">OPTIONAL value that scopes the search for members based on access modifiers.  DEFAULT is to include members having any supported access modifier.</param>
        /// <param name="memberAttributes">OPTIONAL value that scopes the search for members based on the presence or absence of certain attributes on those members.  DEFAULT is to include members that are not compiler generated.</param>
        /// <param name="orderMembersBy">OPTIONAL value that specifies how to the members.  DEFAULT is return the members in no particular order.</param>
        /// <returns>
        /// The methods in the specified order.
        /// </returns>
        /// <exception cref="ArgumentNullException"><paramref name="type"/> is null.</exception>
        public static IReadOnlyList <MethodInfo> GetMethodsFiltered(
            this Type type,
            MemberRelationships memberRelationships = MemberRelationships.DeclaredOrInherited,
            MemberOwners memberOwners = MemberOwners.All,
            MemberAccessModifiers memberAccessModifiers = MemberAccessModifiers.All,
            MemberAttributes memberAttributes           = MemberAttributes.NotCompilerGenerated,
            OrderMembersBy orderMembersBy = OrderMembersBy.None)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            var result = type
                         .GetMembersFiltered(memberRelationships, memberOwners, memberAccessModifiers, MemberKinds.Method, MemberMutability.All, memberAttributes, orderMembersBy)
                         .Cast <MethodInfo>()
                         .ToList();

            return(result);
        }