public void Add()
        {
            CodeTypeParameter tp1 = new CodeTypeParameter();
            CodeTypeParameter tp2 = new CodeTypeParameter();

            CodeTypeParameterCollection coll = new CodeTypeParameterCollection();

            Assert.AreEqual(0, coll.Add(tp1), "#1");
            Assert.AreEqual(1, coll.Count, "#2");
            Assert.AreEqual(0, coll.IndexOf(tp1), "#3");

            Assert.AreEqual(1, coll.Add(tp2), "#4");
            Assert.AreEqual(2, coll.Count, "#5");
            Assert.AreEqual(1, coll.IndexOf(tp2), "#6");
        }
        public void Constructor2()
        {
            CodeTypeParameter tp1 = new CodeTypeParameter();
            CodeTypeParameter tp2 = new CodeTypeParameter();

            CodeTypeParameterCollection c = new CodeTypeParameterCollection();

            c.Add(tp1);
            c.Add(tp2);

            CodeTypeParameterCollection coll = new CodeTypeParameterCollection(c);

            Assert.AreEqual(2, coll.Count, "#1");
            Assert.AreEqual(0, coll.IndexOf(tp1), "#2");
            Assert.AreEqual(1, coll.IndexOf(tp2), "#3");
        }
예제 #3
0
        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);
            }
        }
예제 #4
0
 private void FillGenericParameters(CodeTypeParameterCollection codes, IEnumerable <GenericParameter> defines)
 {
     foreach (var genericParameter in defines)
     {
         CodeTypeParameter t = new CodeTypeParameter(genericParameter.FullName);
         if (genericParameter.IsContravariant)
         {
             t.HasConstructorConstraint = true;
         }
         foreach (var constraint in genericParameter.Constraints)
         {
             t.Constraints.Add(new CodeTypeReference(constraint.FullName));
         }
         FillCustomAttribute(t.CustomAttributes, genericParameter.CustomAttributes);
         codes.Add(t);
     }
 }
예제 #5
0
        private static void PopulateGenericParameters(IGenericParameterProvider publicType,
                                                      CodeTypeParameterCollection parameters)
        {
            foreach (var parameter in publicType.GenericParameters)
            {
                if (parameter.HasCustomAttributes)
                {
                    throw new NotImplementedException("Attributes on type parameters is not supported. And weird");
                }

                // 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, which looks even weirder
                var name = parameter.Name;
                if (parameter.IsCovariant)
                {
                    name = "out " + name;
                }
                if (parameter.IsContravariant)
                {
                    name = "in " + name;
                }

                var typeParameter = new CodeTypeParameter(name)
                {
                    HasConstructorConstraint =
                        parameter.HasDefaultConstructorConstraint && !parameter.HasNotNullableValueTypeConstraint
                };
                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"))
                {
                    typeParameter.Constraints.Add(CreateCodeTypeReference(constraint.GetElementType()));
                }
                parameters.Add(typeParameter);
            }
        }
        void WriteTypeParameters(CodeTypeParameterCollection typeParameters, IndentedTextWriter writer, out string typeConstraints)
        {
            var constraints = string.Empty;

            if (typeParameters.Count > 0)
            {
                var parameterDeclarations = typeParameters.Cast <CodeTypeParameter>().Select(p =>
                {
                    if (p.Constraints.Count > 0 || p.HasConstructorConstraint)
                    {
                        var parameterConstraints = new List <string>(p.Constraints.Count);
                        parameterConstraints.AddRange(p.Constraints.Cast <CodeTypeReference>().Select(type =>
                        {
                            if (type.BaseType == "System.ValueType")
                            {
                                return("struct");
                            }
                            else if (type.BaseType == "System.Object")
                            {
                                return("class");
                            }
                            else
                            {
                                return(GetTypeOutput(type));
                            }
                        }));
                        if (p.HasConstructorConstraint)
                        {
                            parameterConstraints.Add("new()");
                        }
                        constraints += $" where {p.Name} : {string.Join(", ", parameterConstraints)}";
                    }
                    return(p.Name);
                });
                writer.Write($"<{string.Join(", ", parameterDeclarations)}>");
            }
            typeConstraints = constraints;
        }
예제 #7
0
        public static CodeTypeParameterCollection GenericTypeParameters(Type t)
        {
            if (!t.IsGenericType)
            {
                return(null);
            }

            var p = new CodeTypeParameterCollection();

            foreach (var genericParameter in t.GetGenericTypeDefinition().GetGenericArguments())
            {
                var param = new CodeTypeParameter(genericParameter.Name);
                if ((genericParameter.GenericParameterAttributes &
                     GenericParameterAttributes.ReferenceTypeConstraint) != GenericParameterAttributes.None)
                {
                    param.Constraints.Add(" class");
                }
                if ((genericParameter.GenericParameterAttributes &
                     GenericParameterAttributes.NotNullableValueTypeConstraint) != GenericParameterAttributes.None)
                {
                    param.Constraints.Add(" struct");
                }
                var constraints = genericParameter.GetGenericParameterConstraints();
                foreach (var constraintType in constraints)
                {
                    param.Constraints.Add(
                        new CodeTypeReference(TypeUtils.GetParameterizedTemplateName(constraintType, false,
                                                                                     x => true)));
                }
                if ((genericParameter.GenericParameterAttributes &
                     GenericParameterAttributes.DefaultConstructorConstraint) != GenericParameterAttributes.None)
                {
                    param.HasConstructorConstraint = true;
                }
                p.Add(param);
            }
            return(p);
        }
예제 #8
0
        /// <summary>
        /// Generates a wrapper method that takes arguments of the original method.
        /// </summary>
        protected override CodeTypeMember GetBasicReferenceMethod(MethodInfo methodInfo, CodeTypeParameterCollection genericTypeParam, bool isObserver)
        {
            SerializerGenerationManager.RecordTypeToGenerate(methodInfo.ReturnType);
            foreach (ParameterInfo paramInfo in methodInfo.GetParameters())
            {
                SerializerGenerationManager.RecordTypeToGenerate(paramInfo.ParameterType);
            }

            if (!isObserver)
            {
                var parameterList = new StringBuilder();
                var first         = true;
                foreach (var p in methodInfo.GetParameters())
                {
                    if (!first)
                    {
                        parameterList.Append(", ");
                    }
                    first = false;
                    parameterList.AppendFormat("{0} As {1}", p.Name, GetGenericTypeName(p.ParameterType, type => { }, t => false));
                }

                var snippet = new StringBuilder();
                snippet.AppendFormat("Public Function {0}({1}) As {2} Implements {3}.{0}\n",
                                     methodInfo.Name,
                                     parameterList,
                                     GetGenericTypeName(methodInfo.ReturnType, type => { }, t => false),
                                     GetGenericTypeName(methodInfo.DeclaringType, type => { }, t => false));
                snippet.AppendFormat("            {0}\n", GetBasicMethodImpl(methodInfo));
                snippet.Append("        End Function\n");
                return(new CodeSnippetTypeMember(snippet.ToString()));
            }

            var referenceMethod = new CodeMemberMethod
            {
                Name       = methodInfo.Name,
                ReturnType = GetReturnTypeReference(methodInfo.ReturnType, SerializeFlag.DeserializeResult)
            };

            foreach (var paramInfo in methodInfo.GetParameters())
            {
                referenceMethod.Parameters.Add(new CodeParameterDeclarationExpression(
                                                   new CodeTypeReference(paramInfo.ParameterType), GrainInterfaceData.GetParameterName(paramInfo)));
            }

            referenceMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            var pit = new CodeTypeReference(GetGenericTypeName(methodInfo.DeclaringType, type => { }, t => false));

            referenceMethod.PrivateImplementationType = pit;

            var methodImpl = new CodeSnippetStatement(GetBasicMethodImpl(methodInfo));

            referenceMethod.Statements.Add(methodImpl);
            return(referenceMethod);
        }
예제 #9
0
 public CodeTypeParameterCollection(CodeTypeParameterCollection value)
 {
 }
        public void Add_Null()
        {
            CodeTypeParameterCollection coll = new CodeTypeParameterCollection();

            coll.Add((CodeTypeParameter)null);
        }
예제 #11
0
        private void AddMethods(MethodInfo[] methods, CodeTypeDeclaration referenceClass, CodeTypeParameterCollection genericTypeParam, bool isObserver)
        {
            methodIdCollisionDetection.Clear();
            if (methods == null || methods.Length <= 0)
            {
                return;
            }

            foreach (var methodInfo in methods)
            {
                AddMethod(methodInfo, referenceClass, genericTypeParam, isObserver);
            }
        }
예제 #12
0
        private CodeTypeDeclaration GetInvokerClass(GrainInterfaceData si, bool isClient)
        {
            Type grainType = si.Type;
            CodeTypeParameterCollection genericTypeParams = si.GenericTypeParams;

            var invokerClass = new CodeTypeDeclaration(si.InvokerClassBaseName);

            if (genericTypeParams != null)
            {
                invokerClass.TypeParameters.AddRange(genericTypeParams);
            }

            invokerClass.IsClass = true;
            MarkAsGeneratedCode(invokerClass);
            invokerClass.BaseTypes.Add(si.IsExtension
                ? new CodeTypeReference(typeof(IGrainExtensionMethodInvoker), CodeTypeReferenceOptions.GlobalReference)
                : new CodeTypeReference(typeof(IGrainMethodInvoker), CodeTypeReferenceOptions.GlobalReference));

            GrainInterfaceInfo grainInterfaceInfo = GetInterfaceInfo(grainType);
            var interfaceId = grainInterfaceInfo.Interfaces.Keys.First();

            invokerClass.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(MethodInvokerAttribute), CodeTypeReferenceOptions.GlobalReference),
                                                                           new CodeAttributeArgument(new CodePrimitiveExpression(grainType.Namespace + "." + TypeUtils.GetParameterizedTemplateName(grainType))),
                                                                           new CodeAttributeArgument(new CodePrimitiveExpression(interfaceId))));

            var interfaceIdProperty = new CodeMemberProperty
            {
                Name       = "InterfaceId",
                Attributes = MemberAttributes.Public | MemberAttributes.Final,
                Type       = new CodeTypeReference(typeof(int))
            };

            interfaceIdProperty.GetStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(interfaceId)));
            interfaceIdProperty.PrivateImplementationType = new CodeTypeReference(typeof(IGrainMethodInvoker), CodeTypeReferenceOptions.GlobalReference);
            invokerClass.Members.Add(interfaceIdProperty);

            //Add invoke method for Orleans message
            var orleansInvoker = new CodeMemberMethod
            {
                Attributes = MemberAttributes.Public | MemberAttributes.Final,
                Name       = "Invoke",
                ReturnType = new CodeTypeReference(typeof(Task <object>), CodeTypeReferenceOptions.GlobalReference)
            };

            orleansInvoker.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IAddressable), CodeTypeReferenceOptions.GlobalReference), "grain"));
            orleansInvoker.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "interfaceId"));
            orleansInvoker.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "methodId"));
            orleansInvoker.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object[]), "arguments"));
            orleansInvoker.PrivateImplementationType = new CodeTypeReference(typeof(IGrainMethodInvoker), CodeTypeReferenceOptions.GlobalReference);

            var orleansInvokerImpl = new CodeSnippetStatement(GetInvokerImpl(si, invokerClass, grainType, grainInterfaceInfo, isClient));

            orleansInvoker.Statements.Add(orleansInvokerImpl);
            invokerClass.Members.Add(orleansInvoker);

            //Add TryInvoke method for Orleans message, if the type is an extension interface
            if (si.IsExtension)
            {
                var orleansTryInvoker = new CodeMemberMethod
                {
                    Attributes = MemberAttributes.Public | MemberAttributes.Final,
                    Name       = "Invoke",
                    ReturnType = new CodeTypeReference(typeof(Task <object>), CodeTypeReferenceOptions.GlobalReference)
                };
                orleansTryInvoker.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IGrainExtension), CodeTypeReferenceOptions.GlobalReference), "grain"));
                orleansTryInvoker.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "interfaceId"));
                orleansTryInvoker.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "methodId"));
                orleansTryInvoker.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object[]), "arguments"));
                orleansTryInvoker.PrivateImplementationType = new CodeTypeReference(typeof(IGrainExtensionMethodInvoker), CodeTypeReferenceOptions.GlobalReference);

                var orleansTryInvokerImp = new CodeSnippetStatement(GetInvokerImpl(si, invokerClass, grainType, grainInterfaceInfo, isClient));
                orleansTryInvoker.Statements.Add(orleansTryInvokerImp);
                invokerClass.Members.Add(orleansTryInvoker);
            }

            //Add GetMethodName() method
            var getMethodName = new CodeMemberMethod
            {
                Attributes = MemberAttributes.Public | MemberAttributes.Final | MemberAttributes.Static,
                Name       = "GetMethodName",
                ReturnType = new CodeTypeReference(typeof(string))
            };

            getMethodName.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "interfaceId"));
            getMethodName.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "methodId"));

            var orleansGetMethodNameImpl = new CodeSnippetStatement(GetOrleansGetMethodNameImpl(grainType, grainInterfaceInfo));

            getMethodName.Statements.Add(orleansGetMethodNameImpl);
            invokerClass.Members.Add(getMethodName);
            return(invokerClass);
        }
예제 #13
0
        protected virtual CodeTypeDeclaration GetStateClass(
            GrainInterfaceData grainInterfaceData,
            Action <Type> referred,
            string stateClassBaseName,
            string stateClassName,
            out bool hasStateClass)
        {
            var sourceType = grainInterfaceData.Type;

            stateClassName = FixupTypeName(stateClassName);
            CodeTypeParameterCollection genericTypeParams = grainInterfaceData.GenericTypeParams;

            Func <Type, bool> nonamespace = t => CurrentNamespace == t.Namespace || ReferencedNamespaces.Contains(t.Namespace);

            Type persistentInterface = GetPersistentInterface(sourceType);
            Dictionary <string, PropertyInfo> asyncProperties = GrainInterfaceData.GetPersistentProperties(persistentInterface)
                                                                .ToDictionary(p => p.Name.Substring(p.Name.LastIndexOf('.') + 1), p => p);

            Dictionary <string, string> properties = asyncProperties.ToDictionary(p => p.Key,
                                                                                  p => GetGenericTypeName(GrainInterfaceData.GetPromptType(p.Value.PropertyType), referred, nonamespace));

            var stateClass = new CodeTypeDeclaration(stateClassBaseName);

            if (genericTypeParams != null)
            {
                stateClass.TypeParameters.AddRange(genericTypeParams);
            }
            stateClass.IsClass = true;

            if (persistentInterface != null)
            {
                stateClass.TypeAttributes = persistentInterface.IsPublic ? TypeAttributes.Public : TypeAttributes.NotPublic;
            }
            else
            {
                stateClass.TypeAttributes = TypeAttributes.Public;
            }

            stateClass.BaseTypes.Add(new CodeTypeReference(typeof(GrainState), CodeTypeReferenceOptions.GlobalReference));
            MarkAsGeneratedCode(stateClass);
            referred(typeof(GrainState));

            if (persistentInterface != null)
            {
                stateClass.BaseTypes.Add(new CodeTypeReference(GetGenericTypeName(persistentInterface, referred, nonamespace)));
            }

            stateClass.CustomAttributes.Add(new CodeAttributeDeclaration(typeof(SerializableAttribute).Name));
            stateClass.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(GrainStateAttribute), CodeTypeReferenceOptions.GlobalReference),
                                                                         new CodeAttributeArgument(new CodePrimitiveExpression(grainInterfaceData.Type.Namespace + "." + TypeUtils.GetParameterizedTemplateName(grainInterfaceData.Type)))));

            referred(typeof(SerializableAttribute));
            referred(typeof(OnDeserializedAttribute));

            var initStateFields = new CodeMemberMethod {
                Name = "InitStateFields"
            };

            initStateFields.Attributes = (initStateFields.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Private;
            foreach (var peoperty in asyncProperties)
            {
                Type propertyType = peoperty.Value.PropertyType;

                bool noCreateNew = propertyType.IsPrimitive || typeof(string).IsAssignableFrom(propertyType) || // Primative types
                                   propertyType.IsAbstract || propertyType.IsInterface || propertyType.IsGenericParameter || // No concrete implementation
                                   propertyType.GetConstructor(Type.EmptyTypes) == null; // No default constructor

                var initExpression = noCreateNew                                         // Pre-initialize this type to default value
                    ? (CodeExpression) new CodeDefaultValueExpression(new CodeTypeReference(GetGenericTypeName(propertyType, referred, nonamespace)))
                    : new CodeObjectCreateExpression(new CodeTypeReference(GetGenericTypeName(propertyType, referred, nonamespace)));

                initStateFields.Statements.Add(new CodeAssignStatement(
                                                   new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), peoperty.Key),
                                                   initExpression));
            }

            hasStateClass = properties.Count > 0;

            if (hasStateClass)
            {
                foreach (var pair in properties)
                {
                    GenerateStateClassProperty(stateClass, asyncProperties[pair.Key], pair.Key, pair.Value);
                }

                var returnType = new CodeTypeReference("System.Collections.Generic.IDictionary",
                                                       new CodeTypeReference(typeof(string)), new CodeTypeReference(typeof(object)));
                var concreteType = new CodeTypeReference("System.Collections.Generic.Dictionary",
                                                         new CodeTypeReference(typeof(string)), new CodeTypeReference(typeof(object)));

                var asDictionary = new CodeMemberMethod
                {
                    Name       = "AsDictionary",
                    Attributes = MemberAttributes.Public | MemberAttributes.Override,
                    ReturnType = returnType
                };

                asDictionary.Statements.Add(new CodeVariableDeclarationStatement(concreteType, "result", new CodeObjectCreateExpression(concreteType)));
                foreach (var pair in properties)
                {
                    asDictionary.Statements.Add(new CodeAssignStatement(
                                                    new CodeIndexerExpression(new CodeVariableReferenceExpression("result"), new CodePrimitiveExpression(pair.Key)),
                                                    new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), pair.Key)));
                }

                asDictionary.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("result")));
                stateClass.Members.Add(asDictionary);

                GenerateSetAll(stateClass, properties);
                GenerateToString(stateClass, stateClassName, properties);
            }

            // Copier, serializer, and deserializer for the state class
            var copier       = SerializerGenerationUtilities.GenerateCopier("_Copier", stateClassName, genericTypeParams);
            var serializer   = SerializerGenerationUtilities.GenerateSerializer("_Serializer", stateClassName, genericTypeParams);
            var deserializer = SerializerGenerationUtilities.GenerateDeserializer("_Deserializer", stateClassName, genericTypeParams);

            var ctor = new CodeConstructor {
                Attributes = (copier.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public
            };

            ctor.BaseConstructorArgs.Add(new CodePrimitiveExpression(TypeUtils.GetFullName(grainInterfaceData.Type)));
            ctor.Statements.Add(new CodeMethodInvokeExpression(
                                    new CodeThisReferenceExpression(),
                                    "InitStateFields"));

            copier.Statements.Add(new CodeMethodReturnStatement(
                                      new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("input"), "DeepCopy")));

            serializer.Statements.Add(
                new CodeMethodInvokeExpression(
                    new CodeVariableReferenceExpression("input"),
                    "SerializeTo", new CodeArgumentReferenceExpression("stream")));

            deserializer.Statements.Add(new CodeVariableDeclarationStatement(stateClassName, "result",
                                                                             new CodeObjectCreateExpression(stateClassName)));
            deserializer.Statements.Add(new CodeMethodInvokeExpression(
                                            new CodeVariableReferenceExpression("result"),
                                            "DeserializeFrom",
                                            new CodeArgumentReferenceExpression("stream")));
            deserializer.Statements.Add(new CodeMethodReturnStatement(
                                            new CodeVariableReferenceExpression("result")));

            stateClass.Members.Add(ctor);
            stateClass.Members.Add(initStateFields);
            stateClass.Members.Add(copier);
            stateClass.Members.Add(serializer);
            stateClass.Members.Add(deserializer);

            return(stateClass);
        }
	public void AddRange(CodeTypeParameterCollection value) {}
        public void Remove_Null()
        {
            CodeTypeParameterCollection coll = new CodeTypeParameterCollection();

            coll.Remove((CodeTypeParameter)null);
        }
 public void Constructor1_Null()
 {
     CodeTypeParameterCollection coll = new CodeTypeParameterCollection(
         (CodeTypeParameter[])null);
 }
        public void Remove_NotInCollection()
        {
            CodeTypeParameterCollection coll = new CodeTypeParameterCollection();

            coll.Remove(new CodeTypeParameter());
        }
        public void AddRange_Null_Collection()
        {
            CodeTypeParameterCollection coll = new CodeTypeParameterCollection();

            coll.AddRange((CodeTypeParameterCollection)null);
        }
        public void Insert_Null()
        {
            CodeTypeParameterCollection coll = new CodeTypeParameterCollection();

            coll.Insert(0, (CodeTypeParameter)null);
        }
예제 #20
0
        protected override CodeTypeDeclaration GetStateClass(GrainInterfaceData grainInterfaceData, Action <Type> referred, string stateClassBaseName, string stateClassName, out bool hasStateClass)
        {
            var sourceType = grainInterfaceData.Type;

            stateClassName = FixupTypeName(stateClassName);
            CodeTypeParameterCollection genericTypeParams = grainInterfaceData.GenericTypeParams;
            Func <Type, bool>           nonamespace       = t => false;
            Type persistentInterface = GetPersistentInterface(sourceType);

            Dictionary <string, PropertyInfo> asyncProperties = GrainInterfaceData.GetPersistentProperties(persistentInterface)
                                                                .ToDictionary(p => p.Name.Substring(p.Name.LastIndexOf('.') + 1), p => p);

            Dictionary <string, string> properties = asyncProperties.ToDictionary(p => p.Key,
                                                                                  p => GetGenericTypeName(GrainInterfaceData.GetPromptType(p.Value.PropertyType), referred, nonamespace));

            hasStateClass = properties.Count > 0;

            if (!hasStateClass)
            {
                return(null);
            }

            var typeAccess = (persistentInterface != null && !persistentInterface.IsPublic) ? "internal" : "public";

            StartNewLine();
            StartNewLine();
            generatedCode.AppendFormat(@"[<System.CodeDom.Compiler.GeneratedCodeAttribute(""{0}"", ""{1}"")>]", CODE_GENERATOR_NAME, CodeGeneratorVersion);
            StartNewLine();
            generatedCode.AppendFormat(@"[<System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()>]");
            StartNewLine();
            generatedCode.AppendFormat(@"[<System.SerializableAttribute()>]");
            StartNewLine();
            var grainName = grainInterfaceData.Type.Namespace + "." + TypeUtils.GetParameterizedTemplateName(grainInterfaceData.Type);

            generatedCode.AppendFormat(@"[<global.Orleans.CodeGeneration.GrainStateAttribute(""{0}"")>]", grainName);
            StartNewLine();
            generatedCode.AppendFormat(@"type {0} {1}", typeAccess, stateClassBaseName);

            if (genericTypeParams != null && genericTypeParams.Count > 0)
            {
                generatedCode.Append('<');
                for (int p = 0; p < genericTypeParams.Count; ++p)
                {
                    if (p > 0)
                    {
                        generatedCode.Append(',');
                    }

                    CodeTypeParameter param = genericTypeParams[p];
                    generatedCode.Append('\'').Append(param.Name);
                }
                generatedCode.Append('>');
            }

            generatedCode.AppendFormat(@"() =");
            IncreaseIndent();
            StartNewLine();
            generatedCode.AppendFormat(@"inherit global.Orleans.CodeGeneration.GrainState(""{0}"")", grainName);
            StartNewLine();

            var declaringTypes = new Dictionary <string, List <KeyValuePair <string, PropertyInfo> > >();

            foreach (var pair in asyncProperties)
            {
                var dtName = GetGenericTypeName(pair.Value.DeclaringType, referred, nonamespace);
                if (!declaringTypes.ContainsKey(dtName))
                {
                    declaringTypes.Add(dtName, new List <KeyValuePair <string, PropertyInfo> >());
                }

                var lst = declaringTypes[dtName];
                lst.Add(pair);
            }

            foreach (var declaringType in declaringTypes)
            {
                StartNewLine();
                generatedCode.AppendFormat(@"interface {0} with", declaringType.Key);

                IncreaseIndent();
                foreach (var pair in declaringType.Value)
                {
                    var propertyType = pair.Value.PropertyType;

                    bool noCreateNew = propertyType.IsPrimitive || typeof(string).IsAssignableFrom(propertyType) || // Primative types
                                       propertyType.IsAbstract || propertyType.IsInterface || propertyType.IsGenericParameter || // No concrete implementation
                                       propertyType.GetConstructor(Type.EmptyTypes) == null; // No default constructor

                    var initExpr = noCreateNew ?
                                   string.Format("Unchecked.defaultof<{0}>", GetGenericTypeName(propertyType, referred, nonamespace)) :
                                   string.Format("{0}()", GetGenericTypeName(propertyType, referred, nonamespace));

                    StartNewLine();
                    generatedCode.AppendFormat(@"override val {0} = {1} with get,set", pair.Key, initExpr);
                }
                DecreaseIndent();
            }

            GenerateSetAll(asyncProperties, referred);
            GenerateAsDictionary(asyncProperties, referred);
            GenerateToString(stateClassName, asyncProperties, referred);

            // Generate the serialization members.

            StartNewLine();
            StartNewLine();
            generatedCode.AppendFormat(@"[<global.Orleans.CodeGeneration.CopierMethodAttribute()>]");
            StartNewLine();
            generatedCode.AppendFormat(@"static member public _Copier(original:obj) : obj =");
            IncreaseIndent();
            StartNewLine();
            generatedCode.AppendFormat(@"let input = original :?> {0}", stateClassBaseName);
            StartNewLine();
            generatedCode.AppendFormat(@"input.DeepCopy() :> obj");
            DecreaseIndent();

            StartNewLine();
            StartNewLine();
            generatedCode.AppendFormat(@"[<global.Orleans.CodeGeneration.SerializerMethodAttribute()>]");
            StartNewLine();
            generatedCode.AppendFormat(@"static member public _Serializer(original:obj, stream:global.Orleans.Serialization.BinaryTokenStreamWriter, expected:System.Type) : unit =");
            IncreaseIndent();
            StartNewLine();
            generatedCode.AppendFormat(@"let input = original :?> {0}", stateClassBaseName);
            StartNewLine();
            generatedCode.AppendFormat(@"input.SerializeTo(stream)");
            DecreaseIndent();

            StartNewLine();
            StartNewLine();
            generatedCode.AppendFormat(@"[<global.Orleans.CodeGeneration.DeserializerMethodAttribute()>]");
            StartNewLine();
            generatedCode.AppendFormat(@"static member public _Deserializer(expected:System.Type, stream:global.Orleans.Serialization.BinaryTokenStreamReader) : obj =");
            IncreaseIndent();
            StartNewLine();
            generatedCode.AppendFormat(@"let result = {0}()", stateClassBaseName);
            StartNewLine();
            generatedCode.AppendFormat(@"result.DeserializeFrom(stream)");
            StartNewLine();
            generatedCode.AppendFormat(@"result :> obj");
            DecreaseIndent();

            DecreaseIndent();

            return(null);
        }
	public CodeTypeParameterCollection(CodeTypeParameterCollection value) {}
예제 #22
0
 /// <summary>
 /// Generates a wrapper method that takes arguments of the original method.
 /// </summary>
 protected override CodeTypeMember GetBasicReferenceMethod(MethodInfo methodInfo, CodeTypeParameterCollection genericTypeParam, bool isObserver)
 {
     throw new NotImplementedException("GetBasicReferenceMethod");
 }
예제 #23
0
 public void AddRange(CodeTypeParameterCollection value)
 {
 }
예제 #24
0
        /// <summary>
        /// Generates a wrapper method that takes arguments of the original method.
        /// </summary>
        protected virtual CodeTypeMember GetBasicReferenceMethod(MethodInfo methodInfo, CodeTypeParameterCollection genericTypeParam, bool isObserver)
        {
            SerializerGenerationManager.RecordTypeToGenerate(methodInfo.ReturnType);
            foreach (var paramInfo in methodInfo.GetParameters())
            {
                SerializerGenerationManager.RecordTypeToGenerate(paramInfo.ParameterType);
            }

            CodeTypeReference returnType;

            if (!isObserver)
            {
                // Method is expected to return either a Task or a grin reference
                if (!GrainInterfaceData.IsTaskType(methodInfo.ReturnType) &&
                    !typeof(IAddressable).IsAssignableFrom(methodInfo.ReturnType))
                {
                    throw new InvalidOperationException(
                              string.Format("Unsupported return type {0}. Method Name={1} Declaring Type={2}",
                                            methodInfo.ReturnType.FullName, methodInfo.Name,
                                            TypeUtils.GetFullName(methodInfo.DeclaringType)));
                }

                returnType = CreateCodeTypeReference(methodInfo.ReturnType);
            }
            else
            {
                returnType = new CodeTypeReference(typeof(void));
            }

            var referenceMethod = new CodeMemberMethod
            {
                Name       = methodInfo.Name,
                ReturnType = returnType
            };

            foreach (var param in methodInfo.GetParameters())
            {
                CodeParameterDeclarationExpression p = param.ParameterType.IsGenericType
                    ? new CodeParameterDeclarationExpression(
                    TypeUtils.GetParameterizedTemplateName(param.ParameterType, true,
                                                           tt => CurrentNamespace != tt.Namespace && !ReferencedNamespaces.Contains(tt.Namespace)),
                    param.Name)
                    : new CodeParameterDeclarationExpression(param.ParameterType, param.Name);

                p.Direction = FieldDirection.In;
                referenceMethod.Parameters.Add(p);
            }

            referenceMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            var pit = new CodeTypeReference(GetGenericTypeName(methodInfo.DeclaringType, type => { }, t => false));

            referenceMethod.PrivateImplementationType = pit;

            var methodImpl = new CodeSnippetStatement(GetBasicMethodImpl(methodInfo));

            referenceMethod.Statements.Add(methodImpl);
            return(referenceMethod);
        }
        internal static CodeMemberMethod GenerateCopier(string name, string typeName, CodeTypeParameterCollection genericTypeParams = null)
        {
            var copier = new CodeMemberMethod {
                Name = name
            };

            copier.Attributes = (copier.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
            copier.Attributes = (copier.Attributes & ~MemberAttributes.ScopeMask) | MemberAttributes.Static;
            copier.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(CopierMethodAttribute), CodeTypeReferenceOptions.GlobalReference)));
            copier.ReturnType = new CodeTypeReference(typeof(object));
            copier.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "original"));
            copier.Statements.Add(new CodeVariableDeclarationStatement(typeName, "input", new CodeCastExpression(typeName, new CodeArgumentReferenceExpression("original"))));
            return(copier);
        }
예제 #26
0
        internal void AddReferenceClass(GrainInterfaceData interfaceData)
        {
            bool isObserver = IsObserver(interfaceData.Type);
            CodeTypeParameterCollection genericTypeParam = interfaceData.GenericTypeParams;

            // Declare factory class
            var factoryClass = new CodeTypeDeclaration(interfaceData.FactoryClassBaseName);

            if (genericTypeParam != null)
            {
                factoryClass.TypeParameters.AddRange(genericTypeParam);
            }

            factoryClass.IsClass        = true;
            factoryClass.TypeAttributes = interfaceData.Type.IsPublic ? TypeAttributes.Public : TypeAttributes.NotPublic;
            MarkAsGeneratedCode(factoryClass);
            AddFactoryMethods(interfaceData, factoryClass);
            AddCastMethods(interfaceData, true, factoryClass);

            if (ShouldGenerateObjectRefFactory(interfaceData))
            {
                AddCreateObjectReferenceMethods(interfaceData, factoryClass);
            }

            int factoryClassIndex = ReferencedNamespace.Types.Add(factoryClass);

            var referenceClass = new CodeTypeDeclaration(interfaceData.ReferenceClassBaseName);

            if (genericTypeParam != null)
            {
                referenceClass.TypeParameters.AddRange(genericTypeParam);
            }
            referenceClass.IsClass = true;

            referenceClass.BaseTypes.Add(new CodeTypeReference(typeof(GrainReference), CodeTypeReferenceOptions.GlobalReference));
            referenceClass.BaseTypes.Add(new CodeTypeReference(typeof(IAddressable), CodeTypeReferenceOptions.GlobalReference));
            var tref = new CodeTypeReference(interfaceData.Type);

            if (genericTypeParam != null)
            {
                foreach (CodeTypeParameter tp in genericTypeParam)
                {
                    tref.TypeArguments.Add(tp.Name);
                }
            }

            referenceClass.BaseTypes.Add(tref);

            MarkAsGeneratedCode(referenceClass);
            referenceClass.TypeAttributes = TypeAttributes.NestedAssembly;
            referenceClass.CustomAttributes.Add(
                new CodeAttributeDeclaration(new CodeTypeReference(typeof(SerializableAttribute))));

            referenceClass.CustomAttributes.Add(
                new CodeAttributeDeclaration(
                    new CodeTypeReference(typeof(GrainReferenceAttribute), CodeTypeReferenceOptions.GlobalReference),
                    new CodeAttributeArgument(
                        new CodePrimitiveExpression(interfaceData.Type.Namespace + "." + TypeUtils.GetParameterizedTemplateName((interfaceData.Type))))));

            var baseReferenceConstructor2 = new CodeConstructor {
                Attributes = MemberAttributes.FamilyOrAssembly
            };

            baseReferenceConstructor2.Parameters.Add(new CodeParameterDeclarationExpression(
                                                         new CodeTypeReference(typeof(GrainReference), CodeTypeReferenceOptions.GlobalReference), "reference"));

            baseReferenceConstructor2.BaseConstructorArgs.Add(new CodeVariableReferenceExpression("reference"));
            referenceClass.Members.Add(baseReferenceConstructor2);

            var baseReferenceConstructor3 = new CodeConstructor {
                Attributes = MemberAttributes.FamilyOrAssembly
            };

            baseReferenceConstructor3.Parameters.Add(new CodeParameterDeclarationExpression("SerializationInfo", "info"));
            baseReferenceConstructor3.BaseConstructorArgs.Add(new CodeVariableReferenceExpression("info"));
            baseReferenceConstructor3.Parameters.Add(new CodeParameterDeclarationExpression("StreamingContext", "context"));
            baseReferenceConstructor3.BaseConstructorArgs.Add(new CodeVariableReferenceExpression("context"));
            referenceClass.Members.Add(baseReferenceConstructor3);

            var grainRef     = new CodeTypeReference(typeof(GrainReference), CodeTypeReferenceOptions.GlobalReference);
            var refClassName = FixupTypeName(interfaceData.ReferenceClassName);

            // Copier, serializer, and deserializer for this type
            var copier = SerializerGenerationUtilities.GenerateCopier("_Copier", refClassName, genericTypeParam);

            copier.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodeCastExpression(refClassName,
                                           new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(grainRef), "CopyGrainReference", new CodeVariableReferenceExpression("input")))));
            referenceClass.Members.Add(copier);

            var serializer = SerializerGenerationUtilities.GenerateSerializer("_Serializer", refClassName, genericTypeParam);

            serializer.Statements.Add(
                new CodeMethodInvokeExpression(
                    new CodeTypeReferenceExpression(grainRef),
                    "SerializeGrainReference", new CodeVariableReferenceExpression("input"),
                    new CodeArgumentReferenceExpression("stream"),
                    new CodeArgumentReferenceExpression("expected")));
            referenceClass.Members.Add(serializer);

            var deserializer = SerializerGenerationUtilities.GenerateDeserializer("_Deserializer", refClassName, genericTypeParam);

            deserializer.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodeMethodInvokeExpression(
                        new CodeTypeReferenceExpression(refClassName),
                        "Cast",
                        new CodeCastExpression(grainRef,
                                               new CodeMethodInvokeExpression(
                                                   new CodeTypeReferenceExpression(grainRef),
                                                   "DeserializeGrainReference",
                                                   new CodeArgumentReferenceExpression("expected"), new CodeArgumentReferenceExpression("stream"))))));
            referenceClass.Members.Add(deserializer);

            // this private class is the "implementation class" for the interface reference type
            ReferencedNamespace.Types[factoryClassIndex].Members.Add(referenceClass);

            AddCastMethods(interfaceData, false, referenceClass);

            var interfaceId       = GrainInterfaceData.GetGrainInterfaceId(interfaceData.Type);
            var interfaceIdMethod = new CodeMemberProperty
            {
                Name       = "InterfaceId",
                Type       = new CodeTypeReference(typeof(int)),
                Attributes = MemberAttributes.Family | MemberAttributes.Override,
                HasSet     = false,
                HasGet     = true
            };

            interfaceIdMethod.GetStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(interfaceId)));
            referenceClass.Members.Add(interfaceIdMethod);


            var left = new CodeBinaryOperatorExpression(
                new CodeArgumentReferenceExpression("interfaceId"),
                CodeBinaryOperatorType.ValueEquality,
                new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "InterfaceId"));

            var interfaceList = GrainInterfaceData.GetRemoteInterfaces(interfaceData.Type);

            foreach (int iid in interfaceList.Keys)
            {
                if (iid == interfaceId)
                {
                    continue;                     // already covered the main interfaces
                }
                left = new CodeBinaryOperatorExpression(
                    left,
                    CodeBinaryOperatorType.BooleanOr,
                    new CodeBinaryOperatorExpression(
                        new CodeArgumentReferenceExpression("interfaceId"),
                        CodeBinaryOperatorType.ValueEquality,
                        new CodePrimitiveExpression(iid)));
            }

            var interfaceIsCompatibleMethod = new CodeMemberMethod
            {
                Name       = "IsCompatible",
                ReturnType = new CodeTypeReference(typeof(bool))
            };

            interfaceIsCompatibleMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(int)), "interfaceId"));
            interfaceIsCompatibleMethod.Attributes = MemberAttributes.Public | MemberAttributes.Override;
            interfaceIsCompatibleMethod.Statements.Add(new CodeMethodReturnStatement(left));
            referenceClass.Members.Add(interfaceIsCompatibleMethod);

            var interfaceNameMethod = new CodeMemberProperty
            {
                Name       = "InterfaceName",
                Type       = new CodeTypeReference(typeof(string)),
                Attributes = MemberAttributes.Family | MemberAttributes.Override,
                HasSet     = false,
                HasGet     = true
            };

            interfaceNameMethod.GetStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(FixupTypeName(interfaceData.TypeFullName))));
            referenceClass.Members.Add(interfaceNameMethod);

            var invokerClassName = interfaceData.InvokerClassName;

            var getMethodNameMethod = new CodeMemberMethod
            {
                Name       = "GetMethodName",
                ReturnType = new CodeTypeReference(typeof(string))
            };

            getMethodNameMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(int)), "interfaceId"));
            getMethodNameMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(int)), "methodId"));
            getMethodNameMethod.Attributes = MemberAttributes.Family | MemberAttributes.Override;
            var methodInvokerName = string.Format("{0}.GetMethodName", FixupTypeName(invokerClassName));

            getMethodNameMethod.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodeMethodInvokeExpression(
                        null, methodInvokerName,
                        new CodeArgumentReferenceExpression("interfaceId"),
                        new CodeArgumentReferenceExpression("methodId"))));
            referenceClass.Members.Add(getMethodNameMethod);

            CodeTypeDeclaration invokerClass = GetInvokerClass(interfaceData, true);

            invokerClass.TypeAttributes = TypeAttributes.NotPublic;
            ReferencedNamespace.Types.Add(invokerClass);

            ReferencedNamespace.Imports.Add(new CodeNamespaceImport("System"));
            ReferencedNamespace.Imports.Add(new CodeNamespaceImport("System.Net"));
            ReferencedNamespace.Imports.Add(new CodeNamespaceImport("System.Runtime.Serialization"));
            ReferencedNamespace.Imports.Add(new CodeNamespaceImport("System.Runtime.Serialization.Formatters.Binary"));
            ReferencedNamespace.Imports.Add(new CodeNamespaceImport("System.IO"));
            ReferencedNamespace.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));

            MethodInfo[] methods = GrainInterfaceData.GetMethods(interfaceData.Type);
            AddMethods(methods, referenceClass, genericTypeParam, isObserver);
        }
        internal static CodeMemberMethod GenerateSerializer(string name, string typeName, CodeTypeParameterCollection genericTypeParams = null)
        {
            var serializer = new CodeMemberMethod {
                Name = name
            };

            serializer.Attributes = (serializer.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
            serializer.Attributes = (serializer.Attributes & ~MemberAttributes.ScopeMask) | MemberAttributes.Static;
            serializer.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(SerializerMethodAttribute), CodeTypeReferenceOptions.GlobalReference)));
            serializer.ReturnType = new CodeTypeReference(typeof(void));
            serializer.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "original"));
            serializer.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(BinaryTokenStreamWriter), CodeTypeReferenceOptions.GlobalReference), "stream"));
            serializer.Parameters.Add(new CodeParameterDeclarationExpression(typeof(Type), "expected"));
            serializer.Statements.Add(new CodeVariableDeclarationStatement(typeName, "input", new CodeCastExpression(typeName, new CodeArgumentReferenceExpression("original"))));
            return(serializer);
        }
예제 #28
0
        private void AddMethod(MethodInfo methodInfo, CodeTypeDeclaration referenceClass, CodeTypeParameterCollection genericTypeParam, bool isObserver)
        {
            if (methodInfo.IsStatic || IsSpecialEventMethod(methodInfo))
            {
                return; // skip such methods
            }
            int methodId = GrainInterfaceData.ComputeMethodId(methodInfo);

            if (methodIdCollisionDetection.Contains(methodId))
            {
                ReportErrorAndThrow(string.Format("Collision detected for method {0}, declaring type {1}, consider renaming method name",
                                                  methodInfo.Name, methodInfo.DeclaringType.FullName));
            }
            else
            {
                var code = GetBasicReferenceMethod(methodInfo, genericTypeParam, isObserver);
                referenceClass.Members.Add(code); // method with original argument types
                methodIdCollisionDetection.Add(methodId);
            }

            if (typeof(IAddressable).IsAssignableFrom(methodInfo.ReturnType))
            {
                RecordReferencedNamespaceAndAssembly(methodInfo.ReturnType);
            }
        }
        internal static CodeMemberMethod GenerateDeserializer(string name, string typeName, CodeTypeParameterCollection genericTypeParams = null)
        {
            var deserializer = new CodeMemberMethod {
                Name = name
            };

            deserializer.Attributes = (deserializer.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
            deserializer.Attributes = (deserializer.Attributes & ~MemberAttributes.ScopeMask) | MemberAttributes.Static;
            deserializer.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(DeserializerMethodAttribute), CodeTypeReferenceOptions.GlobalReference)));
            deserializer.ReturnType = new CodeTypeReference(typeof(object));
            deserializer.Parameters.Add(new CodeParameterDeclarationExpression(typeof(Type), "expected"));
            deserializer.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(BinaryTokenStreamReader), CodeTypeReferenceOptions.GlobalReference), "stream"));
            return(deserializer);
        }
예제 #30
0
 private void ValidateTypeParameters(CodeTypeParameterCollection parameters)
 {
     for (int i = 0; i < parameters.Count; i++)
     {
         ValidateTypeParameter(parameters[i]);
     }
 }
예제 #31
0
        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);
            }
        }