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); }
/// <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); }
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); } }
/// <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); }
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; }
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); } }