/// <summary>
        /// Determines if the passed type passes the filter criteria or not
        /// </summary>
        /// <param name="ComparisonMode">The type comparison mode to implement</param>
        /// <param name="Item">The item to be evaluated</param>
        /// <param name="FilterItems">The collection of items that the compare item will be compared against</param>
        /// <param name="IsBlacklist">True if it should behave like a blacklist, false if not</param>
        /// <returns>True if the type is considered valid, false if not</returns>
        public static bool IsValidItem(TypeComparison ComparisonMode, Type Item,
                                       IEnumerable <TypeReference> FilterItems, bool IsBlacklist = true)
        {
            Func <Type, Type, bool> evaluationFunc = ComparisonMode.GetTypeComparisonDelegate();

            bool foundMatch = false;

            foreach (TypeReference filterItem in FilterItems)
            {
                foundMatch = evaluationFunc(Item, filterItem);

                if (foundMatch)
                {
                    break;
                }
            }

            if (IsBlacklist)
            {
                return(!foundMatch);
            }
            else
            {
                return(foundMatch);
            }
        }
        /// <summary>
        /// Retrieves the function that should be used to compare two types
        /// based on the selected enum mode
        /// </summary>
        /// <param name="ComparisonMode">The mode to get the function for</param>
        /// <returns>The delegate for evaluating the two types</returns>
        public static Func <Type, Type, bool> GetTypeComparisonDelegate(this TypeComparison ComparisonMode)
        {
            switch (ComparisonMode)
            {
            case TypeComparison.Equals:
                return(CheckTypeEquality);

            case TypeComparison.Inherits:
                return(CheckTypeInherits);

            case TypeComparison.Implements:
                return(CheckTypeImplements);

            default:
                return(null);
            }
        }
        /// <summary>
        /// Determines whether the current <see cref="Type"/> derives from the specified <see cref="Type"/>.
        /// </summary>
        /// <param name="type">The <see cref="Type"/> to check for being a subclass.</param>
        /// <param name="other">The <see cref="Type"/> to check for being the superclass.</param>
        /// <param name="comparisonMethod">The method to use when comparing two <see cref="Type"/> objects.</param>
        /// <returns>True if the type is a subclass, false if not.</returns>
        /// <exception cref="ArgumentException"><paramref name="comparisonMethod"/> is
        ///     not a valid value in <see cref="TypeComparison"/>.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="type"/> or <paramref name="other"/> is null.</exception>
        public static bool IsSubclassOf(this Type type, Type other, TypeComparison comparisonMethod)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }
            if (other == null)
            {
                throw new ArgumentNullException(nameof(other));
            }

            switch (comparisonMethod)
            {
            case TypeComparison.Default:
                return(type.IsSubclassOf(other));

            case TypeComparison.AssemblyQualifiedName:
            {
                var current = type;
                while (current != null)
                {
                    if (string.Equals(current.AssemblyQualifiedName, other.AssemblyQualifiedName, StringComparison.Ordinal))
                    {
                        return(true);
                    }

                    if (current != typeof(object))
                    {
                        current = current.BaseType;
                    }
                    else
                    {
                        break;
                    }
                }

                return(false);
            }

            default:
                throw new ArgumentException($"Invalid {nameof(TypeComparison)} value \"{comparisonMethod}\"!");
            }
        }
        /// <summary>
        /// Determines whether two <see cref="Type"/> objects represent the same type.
        /// </summary>
        /// <param name="type">The current <see cref="Type"/> to check with for equality.</param>
        /// <param name="other">The other <see cref="Type"/> to check against for equality.</param>
        /// <param name="comparisonMethod">The method to use when comparing two <see cref="Type"/> objects.</param>
        /// <returns>True if the types are found to be equal, false if not.</returns>
        /// <exception cref="ArgumentException"><paramref name="comparisonMethod"/> is
        ///     not a valid value in <see cref="TypeComparison"/>.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="type"/> or <paramref name="other"/> is null.</exception>
        public static bool Equals(this Type type, Type other, TypeComparison comparisonMethod)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }
            if (other == null)
            {
                throw new ArgumentNullException(nameof(other));
            }

            switch (comparisonMethod)
            {
            case TypeComparison.Default:
                return(type.Equals(other));

            case TypeComparison.AssemblyQualifiedName:
                return(string.Equals(type.AssemblyQualifiedName, other.AssemblyQualifiedName, StringComparison.Ordinal));

            default:
                throw new ArgumentException($"Invalid {nameof(TypeComparison)} value \"{comparisonMethod}\"!");
            }
        }
Example #5
0
        public static bool CompareTo <TTypes, TOtherTypes>(this TTypes types, TOtherTypes otherTypes, TypeComparison comparisonType)
            where TTypes : IReadOnlyList <Type>
            where TOtherTypes : IReadOnlyList <Type>
        {
            var count = otherTypes.Count;

            if (types.Count != count)
            {
                return(false);
            }

            switch (comparisonType)
            {
            case TypeComparison.Equality:
                for (int i = 0; i < count; ++i)
                {
                    if (types[i] != otherTypes[i])
                    {
                        return(false);
                    }
                }
                return(true);

            case TypeComparison.AssignmentCompatibility:
                for (int i = 0; i < count; ++i)
                {
                    if (types[i].IsAssignableFrom(otherTypes[i]) == false)
                    {
                        return(false);
                    }
                }
                return(true);

            case TypeComparison.TypeMatchersOrElseAssignmentCompatibility:
                for (int i = 0; i < count; ++i)
                {
                    if (types[i].IsTypeMatcher(out var typeMatcherType))
                    {
                        Debug.Assert(typeMatcherType.ImplementsTypeMatcherProtocol());

                        var typeMatcher = (ITypeMatcher)Activator.CreateInstance(typeMatcherType);
                        if (typeMatcher.Matches(otherTypes[i]) == false)
                        {
                            return(false);
                        }
                    }
                    else if (types[i].IsAssignableFrom(otherTypes[i]) == false)
                    {
                        return(false);
                    }
                }
                return(true);

            default:
                throw new ArgumentOutOfRangeException(nameof(comparisonType));
            }
        }