Exemple #1
0
 private static GenericParameterAttributes ToClassGenericParameterAttributes(GenericParameterAttributes attributes)
 {
     if (attributes == GenericParameterAttributes.None)
     {
         return(GenericParameterAttributes.None);
     }
     if (attributes.HasFlag(GenericParameterAttributes.SpecialConstraintMask))
     {
         return(GenericParameterAttributes.SpecialConstraintMask);
     }
     if (attributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint))
     {
         return(GenericParameterAttributes.NotNullableValueTypeConstraint);
     }
     if (attributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint) && attributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint))
     {
         return(GenericParameterAttributes.ReferenceTypeConstraint | GenericParameterAttributes.DefaultConstructorConstraint);
     }
     if (attributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))
     {
         return(GenericParameterAttributes.ReferenceTypeConstraint);
     }
     if (attributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint))
     {
         return(GenericParameterAttributes.DefaultConstructorConstraint);
     }
     return(GenericParameterAttributes.None);
 }
Exemple #2
0
        /// <summary>
        ///     Check whether the specified type match the constraints.
        /// </summary>
        /// <param name="type"> The type to check. </param>
        /// <param name="attributes"> The generic parameter attributes to match. </param>
        /// <param name="typeConstraints"> The constraint type list to match. </param>
        /// <returns>
        ///     <see langword="true" /> if the <paramref name="type" /> match the constraints; otherwise, <see langword="false" />.
        /// </returns>
        public static bool Match(Type type, GenericParameterAttributes attributes, Type[] typeConstraints)
        {
            Ensure.Argument.NotNull(type, "type");
            Ensure.Argument.Satisfy(!type.ContainsGenericParameters, "type",
                                    "The type to check must be a specific type.");

            if (attributes.HasAnyFlag(GenericParameterAttributes.VarianceMask))
            {
                throw new NotSupportedException("Match constraints with variance is not supported.");
            }

            if (attributes.HasAnyFlag(GenericParameterAttributes.SpecialConstraintMask))
            {
                if (attributes.HasFlag((Enum)GenericParameterAttributes.NotNullableValueTypeConstraint)) // struct
                {
                    if (!type.IsValueType)
                    {
                        return(false);
                    }
                }
                else if (attributes.HasFlag((Enum)GenericParameterAttributes.ReferenceTypeConstraint)) // class
                {
                    if (type.IsValueType)
                    {
                        return(false);
                    }
                }

                if (attributes.HasFlag((Enum)GenericParameterAttributes.DefaultConstructorConstraint)) // new()
                {
                    if (!type.IsValueType)
                    {
                        if (type.GetDefaultConstructor() == null)
                        {
                            return(false);
                        }
                    }
                }
            }

            if (typeConstraints.Length > 0)
            {
                foreach (var constraint in typeConstraints)
                {
                    if (!MatchConstraintType(type, constraint))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
        /// <summary>
        /// Return the method signature as a string.
        /// </summary>
        /// <param name="method">
        /// The Method.
        /// </param>
        /// <param name="callable">
        /// Return as an callable string(public void a(string b) would return a(b))
        /// </param>
        /// <param name="convertExtensionsToInstance">
        /// Converts extension methods to an instance signature as if they were defined on the extended class.
        /// </param>
        /// <returns>
        /// Method signature.
        /// </returns>
        public static string GetMethodSignature(MethodInfo method, bool callable = false, bool convertExtensionsToInstance = false)
        {
            // Special case to use interface syntax for GetEnumerator() methods
            if (method.Name.Equals(nameof(IEnumerable.GetEnumerator)) &&
                method.DeclaringType.IsInterface &&
                method.GetParameters().Length == 0)
            {
                return(callable
                    ? "GetEnumerator()"
                    : $"{TypeName(method.ReturnType)} {TypeName(method.DeclaringType)}.GetEnumerator()");
            }

            StringBuilder sigBuilder = new StringBuilder();

            BuildReturnSignature(sigBuilder, method, callable, convertExtensionsToInstance);

            sigBuilder.Append("(");
            sigBuilder.Append(BuildParameterSignature(method.GetParameters(), method, callable, convertExtensionsToInstance));
            sigBuilder.Append(")");

            // Generic constraints

            foreach (Type arg in method.GetGenericArguments())
            {
                List <string> constraints = new List <string>();
                foreach (Type constraint in arg.GetGenericParameterConstraints())
                {
                    constraints.Add(TypeName(constraint));
                }

                GenericParameterAttributes attrs = arg.GenericParameterAttributes;

                if (attrs.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))
                {
                    constraints.Add("class");
                }
                if (attrs.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint))
                {
                    constraints.Add("struct");
                }
                if (attrs.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint))
                {
                    constraints.Add("new()");
                }
                if (constraints.Count > 0 && !callable)
                {
                    sigBuilder.Append(" where " + TypeName(arg) + ": " + string.Join(", ", constraints));
                }
            }

            return(sigBuilder.ToString());
        }
        /// <summary>
        /// Checks if <paramref name="type"/> satisfies all constraints on <paramref name="parameter"/>.
        /// </summary>
        /// <param name="parameter">A generic type parameter.</param>
        /// <param name="type">A <see cref="Type"/> to be checked against <paramref name="parameter"/>.</param>
        /// <param name="context">The <see cref="TypeContext"/> in which the check is being performed.</param>
        /// <returns>True if <paramref name="type"/> satisfies all constraints on <paramref name="parameter"/> and can
        /// be substituted for it in a constructed generic.</returns>
        public static bool CanCloseGenericParameter(Type parameter, Type type, TypeContext context = TypeContext.Default)
        {
            if (parameter == null)
            {
                throw new ArgumentNullException(nameof(parameter));
            }
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }
            if (!parameter.IsGenericParameter)
            {
                throw new ArgumentException("Not a generic parameter", nameof(parameter));
            }
            if (type.ContainsGenericParameters)
            {
                throw new ArgumentException("Not a closed type", nameof(type));
            }

            // Check special attributes

            GenericParameterAttributes attributes = parameter.GenericParameterAttributes;

            if ((attributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint) &&
                 !type.IsByRef) ||
                (attributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint) &&
                 (!type.IsValueType || type.GetInterfaces().Any(x => x.GetGenericTypeDefinition() == typeof(Nullable <>)))) ||
                (attributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint) &&
                 !type.IsValueType && type.GetConstructor(Type.EmptyTypes) == null) ||
                (attributes.HasFlag(GenericParameterAttributes.Covariant) && context == TypeContext.MethodParameter) ||
                (attributes.HasFlag(GenericParameterAttributes.Contravariant) && context == TypeContext.MethodReturn))
            {
                return(false);
            }

            // Check type constraints

            Type[] constraints = parameter.GetGenericParameterConstraints();

            for (int i = 0; i < constraints.Length; i++)
            {
                if (!constraints[i].IsAssignableFrom(type))
                {
                    return(false);
                }
            }

            return(true);
        }
Exemple #5
0
 public ParamModifier GetGenericParamModifier(GenericParameterAttributes attributes)
 {
     if (attributes.HasFlag(GenericParameterAttributes.Contravariant))
     {
         return(ParamModifier.In);
     }
     else if (attributes.HasFlag(GenericParameterAttributes.Covariant))
     {
         return(ParamModifier.Out);
     }
     else
     {
         return(ParamModifier.None);
     }
 }
Exemple #6
0
        /// <summary>
        /// Tries a simple solution to to get a non generic type by using either a built in type or the constraint type
        /// if there is only one.
        /// </summary>
        /// <param name="genericType">The generic type.</param>
        /// <param name="nonGenericType">The non generic type for the <paramref name="genericType"/>.</param>
        /// <returns><see langword="true"/> if a <paramref name="nonGenericType"/> can be used; otherwise
        /// <see langword="false"/>.</returns>
        /// <exception cref="ArgumentNullException">The <paramref name="genericType"/> parameter is
        /// <see langword="null"/>.</exception>
        private static bool TrySimple(Type genericType, out Type nonGenericType)
        {
            if (genericType == null)
            {
                throw new ArgumentNullException(nameof(genericType));
            }

            TypeInfo genericTypeInfo = genericType.GetTypeInfo();

            Type[] constraints = genericTypeInfo.GetGenericParameterConstraints();
            GenericParameterAttributes attributes = genericTypeInfo.GenericParameterAttributes;

            // Handle the simple situation where there are no constraints.
            if (constraints.Length == 0)
            {
                if (attributes == GenericParameterAttributes.None ||
                    attributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))
                {
                    nonGenericType = typeof(object);
                    return(true);
                }
            }

            // Handle the simple situation where the single constraint.
            if (constraints.Length == 1)
            {
                Type constraint = constraints[0];
                if (constraint == typeof(ValueType))
                {
                    nonGenericType = typeof(int);
                    return(true);
                }

                // If there is a single constraint with no attributes, just use the constraint as the non generic type.
                if (attributes == GenericParameterAttributes.None)
                {
                    nonGenericType = constraint;
                    return(true);
                }

                // If there is a single constraint, the generic type requires a default constructor and the constraint
                // has a default constructor, just use the constraint as the non generic type.
                if (attributes == GenericParameterAttributes.DefaultConstructorConstraint)
                {
                    if (constraint.GetTypeInfo().GetConstructor(Type.EmptyTypes) != null)
                    {
                        nonGenericType = constraint;
                        return(true);
                    }
                }
            }

            nonGenericType = null;
            return(false);
        }
        /// <summary>
        /// Create a collection of type parameter constraints for the specified type parameter.
        /// </summary>
        public static List <TypeParameterConstraint> Create(Type typeParameter)
        {
            List <TypeParameterConstraint> typeParameterConstraints = new List <TypeParameterConstraint>();

            foreach (Type typeConstraint in typeParameter.GetGenericParameterConstraints())
            {
                typeParameterConstraints.Add(new TypeConstraint(TypeRef.Create(typeConstraint)));
            }
            GenericParameterAttributes attributes = typeParameter.GenericParameterAttributes;

            if (attributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))  // class constraint
            {
                typeParameterConstraints.Add(new ClassConstraint());
            }
            if (attributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint))  // struct constraint
            {
                typeParameterConstraints.Add(new StructConstraint());
            }
            if (attributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint))
            {
                typeParameterConstraints.Add(new NewConstraint());
            }
            return(typeParameterConstraints);
        }
Exemple #8
0
 private static bool MatchesConstraints(GenericParameterAttributes attributes, Type[] constraints, Type target)
 {
     if (constraints.Length == 0 && attributes == GenericParameterAttributes.None)
     {
         return(true);
     }
     for (int i = 0; i < constraints.Length; i++)
     {
         if (!constraints[i].IsAssignableFrom(target))
         {
             return(false);
         }
     }
     if (attributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint))
     {
         if (target.GetConstructor(new Type[0]) == null)
         {
             return(false);
         }
     }
     if (attributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))
     {
         if (!(target.IsClass || target.IsInterface))
         {
             return(false);
         }
     }
     if (attributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint))
     {
         if (!(target.IsValueType && !target.IsNullable()))
         {
             return(false);
         }
     }
     return(true);
 }
 private static bool MatchesConstraints(GenericParameterAttributes attributes, Type[] constraints, Type target)
 {
     if (constraints.Length == 0 && attributes == GenericParameterAttributes.None)
     {
         return true;
     }
     for (int i = 0; i < constraints.Length; i++)
     {
         if (!constraints[i].IsAssignableFrom(target))
         {
             return false;
         }
     }
     if (attributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint))
     {
         if (target.GetConstructor(new Type[0]) == null) return false;
     }
     if (attributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))
     {
         if (!(target.IsClass || target.IsInterface)) return false;
     }
     if (attributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint))
     {
         if (!(target.IsValueType && !target.IsNullable())) return false;
     }
     return true;
 }
Exemple #10
0
        private static string GenerateCommandManual(string commandName)
        {
            string[] matchingCommands = _commandTable.Keys.Where((string key) => key.Split('(')[0] == commandName).OrderBy((string key) => key).ToArray();
            if (matchingCommands.Length == 0)
            {
                throw new ArgumentException($"No command with the name {commandName} was found.");
            }
            else
            {
                Dictionary <string, ParameterInfo> foundParams           = new Dictionary <string, ParameterInfo>();
                Dictionary <string, Type>          foundGenericArguments = new Dictionary <string, Type>();
                Dictionary <string, CommandParameterDescriptionAttribute> foundParamDescriptions = new Dictionary <string, CommandParameterDescriptionAttribute>();
                List <Type> declaringTypes = new List <Type>(1);

                string manual = $"Generated user manual for {commandName}\nAvailable command signatures:";

                for (int i = 0; i < matchingCommands.Length; i++)
                {
                    CommandData currentCommand = _commandTable[matchingCommands[i]];
                    declaringTypes.Add(currentCommand.MethodData.DeclaringType);

                    manual += $"\n   - {currentCommand.CommandSignature}";
                    if (!currentCommand.IsStatic)
                    {
                        manual += $" (mono-target = {currentCommand.MonoTarget.ToString().ToLower()})";
                    }
                    for (int j = 0; j < currentCommand.ParamCount; j++)
                    {
                        ParameterInfo param = currentCommand.MethodParamData[j];
                        if (!foundParams.ContainsKey(param.Name))
                        {
                            foundParams.Add(param.Name, param);
                        }
                        if (!foundParamDescriptions.ContainsKey(param.Name))
                        {
                            CommandParameterDescriptionAttribute descriptionAttribute = param.GetCustomAttribute <CommandParameterDescriptionAttribute>();
                            if (descriptionAttribute != null && descriptionAttribute.Valid)
                            {
                                foundParamDescriptions.Add(param.Name, descriptionAttribute);
                            }
                        }
                    }

                    if (currentCommand.IsGeneric)
                    {
                        Type[] genericArgs = currentCommand.GenericParamTypes;
                        for (int j = 0; j < genericArgs.Length; j++)
                        {
                            Type arg = genericArgs[j];
                            if (!foundGenericArguments.ContainsKey(arg.Name))
                            {
                                foundGenericArguments.Add(arg.Name, arg);
                            }
                        }
                    }
                }

                if (foundParams.Count > 0)
                {
                    manual += "\nParameter info:";
                    ParameterInfo[] commandParams = foundParams.Values.ToArray();
                    for (int i = 0; i < commandParams.Length; i++)
                    {
                        ParameterInfo currentParam = commandParams[i];
                        manual += $"\n   - {currentParam.Name}: {currentParam.ParameterType.GetDisplayName()}";
                    }
                }

                string genericConstraintInformation = "";
                if (foundGenericArguments.Count > 0)
                {
                    Type[] genericArgs = foundGenericArguments.Values.ToArray();
                    for (int i = 0; i < genericArgs.Length; i++)
                    {
                        Type   arg             = genericArgs[i];
                        Type[] typeConstraints = arg.GetGenericParameterConstraints();
                        GenericParameterAttributes attributes = arg.GenericParameterAttributes;

                        List <string> formattedConstraints = new List <string>();
                        if (attributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint))
                        {
                            formattedConstraints.Add("struct");
                        }
                        if (attributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))
                        {
                            formattedConstraints.Add("class");
                        }
                        for (int j = 0; j < typeConstraints.Length; j++)
                        {
                            formattedConstraints.Add(typeConstraints[i].GetDisplayName());
                        }
                        if (attributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint))
                        {
                            formattedConstraints.Add("new()");
                        }

                        if (formattedConstraints.Count > 0)
                        {
                            genericConstraintInformation += $"\n   - {arg.Name}: {string.Join(", ", formattedConstraints)}";
                        }
                    }
                }
                if (!string.IsNullOrWhiteSpace(genericConstraintInformation))
                {
                    manual += $"\nGeneric constraints:{genericConstraintInformation}";
                }

                for (int i = 0; i < matchingCommands.Length; i++)
                {
                    CommandData currentCommand = _commandTable[matchingCommands[i]];
                    if (currentCommand.HasDescription)
                    {
                        manual += $"\n\nCommand description:\n{currentCommand.CommandDescription}";
                        i       = matchingCommands.Length;
                    }
                }

                if (foundParamDescriptions.Count > 0)
                {
                    manual += "\n\nParameter descriptions:";
                    ParameterInfo[] commandParams = foundParams.Values.ToArray();
                    for (int i = 0; i < commandParams.Length; i++)
                    {
                        ParameterInfo currentParam = commandParams[i];
                        if (foundParamDescriptions.ContainsKey(currentParam.Name))
                        {
                            manual += $"\n - {currentParam.Name}: {foundParamDescriptions[currentParam.Name].Description}";
                        }
                    }
                }

                declaringTypes = declaringTypes.Distinct().ToList();
                manual        += "\n\nDeclared in";
                if (declaringTypes.Count == 1)
                {
                    manual += $" {declaringTypes[0]}";
                }
                else
                {
                    manual += ":";
                    foreach (Type type in declaringTypes)
                    {
                        manual += $"\n   - {type}";
                    }
                }

                return(manual);
            }
        }