static void PopulateGenericParameters(IGenericParameterProvider publicType, CodeTypeParameterCollection parameters, HashSet <string> excludeAttributes) { foreach (var parameter in publicType.GenericParameters) { // A little hacky. Means we get "in" and "out" prefixed on any constraints, but it's either that // or add it as a custom attribute var name = parameter.Name; if (parameter.IsCovariant) { name = "out " + name; } if (parameter.IsContravariant) { name = "in " + name; } var attributeCollection = new CodeAttributeDeclarationCollection(); if (parameter.HasCustomAttributes) { PopulateCustomAttributes(parameter, attributeCollection, excludeAttributes); } var typeParameter = new CodeTypeParameter(name) { HasConstructorConstraint = parameter.HasDefaultConstructorConstraint && !parameter.HasNotNullableValueTypeConstraint }; typeParameter.CustomAttributes.AddRange(attributeCollection.OfType <CodeAttributeDeclaration>().ToArray()); if (parameter.HasNotNullableValueTypeConstraint) { typeParameter.Constraints.Add(" struct"); // Extra space is a hack! } if (parameter.HasReferenceTypeConstraint) { typeParameter.Constraints.Add(" class"); } foreach (var constraint in parameter.Constraints.Where(t => t.FullName != "System.ValueType")) { // for generic constraints like IEnumerable<T> call to GetElementType() returns TypeReference with Name = !0 typeParameter.Constraints.Add(CreateCodeTypeReference(constraint /*.GetElementType()*/)); } parameters.Add(typeParameter); } }
static void PopulateGenericParameters(IGenericParameterProvider publicType, CodeTypeParameterCollection parameters, AttributeFilter attributeFilter, Func <GenericParameter, bool> shouldUseParameter) { foreach (var parameter in publicType.GenericParameters.Where(shouldUseParameter)) { // A little hacky. Means we get "in" and "out" prefixed on any constraints, but it's either that // or add it as a custom attribute var name = parameter.Name; if (parameter.IsCovariant) { name = "out " + name; } if (parameter.IsContravariant) { name = "in " + name; } var attributeCollection = new CodeAttributeDeclarationCollection(); if (parameter.HasCustomAttributes) { PopulateCustomAttributes(parameter, attributeCollection, attributeFilter); } var typeParameter = new CodeTypeParameter(name) { HasConstructorConstraint = parameter.HasDefaultConstructorConstraint && !parameter.HasNotNullableValueTypeConstraint }; typeParameter.CustomAttributes.AddRange(attributeCollection.OfType <CodeAttributeDeclaration>().ToArray()); var nullableConstraint = parameter.GetNullabilityMap().First(); var unmanagedConstraint = parameter.CustomAttributes.Any(attr => attr.AttributeType.FullName == "System.Runtime.CompilerServices.IsUnmanagedAttribute"); if (parameter.HasNotNullableValueTypeConstraint) { typeParameter.Constraints.Add(unmanagedConstraint ? " unmanaged" : " struct"); } if (parameter.HasReferenceTypeConstraint) { typeParameter.Constraints.Add(nullableConstraint == true ? " class?" : " class"); } else if (nullableConstraint == false) { typeParameter.Constraints.Add(" notnull"); } using (NullableContext.Push(parameter)) { foreach (var constraint in parameter.Constraints.Where(constraint => !IsSpecialConstraint(constraint))) { // for generic constraints like IEnumerable<T> call to GetElementType() returns TypeReference with Name = !0 var typeReference = constraint.ConstraintType /*.GetElementType()*/.CreateCodeTypeReference(constraint); typeParameter.Constraints.Add(typeReference); } } parameters.Add(typeParameter); } bool IsSpecialConstraint(GenericParameterConstraint constraint) { // struct if (constraint.ConstraintType is TypeReference reference && reference.FullName == "System.ValueType") { return(true); } // unmanaged if (constraint.ConstraintType.IsUnmanaged()) { return(true); } return(false); } }