private CodeTypeDeclaration GenerateContract(CodeTypeDeclaration proxyClass)
        {
            string domainServiceName = this._domainServiceDescription.DomainServiceType.Name;
            string contractTypeName  = "I" + domainServiceName + "Contract";

            CodeTypeDeclaration contractInterface = CodeGenUtilities.CreateTypeDeclaration(contractTypeName, proxyClass.UserData["Namespace"] as string);

            proxyClass.Members.Add(contractInterface);

            // Add <summary> xml comment to interface
            string comment = string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_DomainContext_ServiceContract_Summary_Comment, domainServiceName);

            contractInterface.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment(comment, this.ClientProxyGenerator.IsCSharp));

            contractInterface.IsInterface = true;
            contractInterface.CustomAttributes.Add(
                CodeGenUtilities.CreateAttributeDeclaration(
                    typeof(ServiceContractAttribute),
                    this.ClientProxyGenerator,
                    proxyClass));

            // Used to track types registered with ServiceKnownTypeAttribute (for Custom methods)
            HashSet <Type> registeredServiceTypes = new HashSet <Type>();

            // Generate query methods, invoke operations and custom methods.
            foreach (DomainOperationEntry operation in this._domainServiceDescription.DomainOperationEntries
                     .Where(op => op.Operation == DomainOperation.Query || op.Operation == DomainOperation.Invoke || op.Operation == DomainOperation.Custom)
                     .OrderBy(op => op.Name))
            {
                if (operation.Operation == DomainOperation.Custom)
                {
                    this.GenerateContractServiceKnownTypes(contractInterface, operation, registeredServiceTypes);
                }
                else
                {
                    this.GenerateContractMethod(contractInterface, operation);
                }
            }

            // Generate submit method if we have CUD operations.
            if (this._domainServiceDescription.DomainOperationEntries
                .Any(op => (op.Operation == DomainOperation.Delete || op.Operation == DomainOperation.Insert ||
                            op.Operation == DomainOperation.Update || op.Operation == DomainOperation.Custom)))
            {
                this.GenerateContractSubmitChangesMethod(contractInterface);
            }

            return(contractInterface);
        }
        /// <summary>
        /// Generates the client proxy code for the given type.
        /// </summary>
        public override void Generate()
        {
            // ----------------------------------------------------------------
            // namespace
            // ----------------------------------------------------------------
            CodeNamespace ns = this.ClientProxyGenerator.GetOrGenNamespace(this.Type);

            // Missing namespace bails out of code-gen -- error has been logged
            if (ns == null)
            {
                return;
            }

            // ----------------------------------------------------------------
            // public partial class {Type} : (Base)
            // ----------------------------------------------------------------
            this.ProxyClass                = CodeGenUtilities.CreateTypeDeclaration(this.Type);
            this.ProxyClass.IsPartial      = true; // makes this a partial type
            this.ProxyClass.TypeAttributes = TypeAttributes.Public;

            // Abstract classes must be preserved as abstract to avoid explicit instantiation on client
            bool isAbstract = (this.Type.IsAbstract);

            if (isAbstract)
            {
                this.ProxyClass.TypeAttributes |= TypeAttributes.Abstract;
            }

            // Determine all types derived from this one.
            // Note this list does not assume the current type is the visible root.  That is a separate test.
            IEnumerable <Type> derivedTypes = this.GetDerivedTypes();

            // If this type doesn't have any derivatives, seal it.  Cannot seal abstracts.
            if (!isAbstract && !derivedTypes.Any())
            {
                this.ProxyClass.TypeAttributes |= TypeAttributes.Sealed;
            }

            // Add all base types including interfaces
            this.AddBaseTypes(ns);
            ns.Types.Add(this.ProxyClass);

            AttributeCollection typeAttributes = this.Type.Attributes();

            // Add <summary> xml comment to class
            string comment = this.GetSummaryComment();

            this.ProxyClass.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment(comment, this.ClientProxyGenerator.IsCSharp));

            // ----------------------------------------------------------------
            // Add default ctr
            // ----------------------------------------------------------------
            CodeConstructor constructor = new CodeConstructor();

            // Default ctor is public for concrete types but protected for abstracts.
            // This prevents direct instantiation on client
            constructor.Attributes = isAbstract ? MemberAttributes.Family : MemberAttributes.Public;

            // add default ctor doc comments
            comment = string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_Default_Constructor_Summary_Comments, this.Type.Name);
            constructor.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment(comment, this.ClientProxyGenerator.IsCSharp));

            // add call to default OnCreated method
            constructor.Statements.Add(this.NotificationMethodGen.OnCreatedMethodInvokeExpression);
            this.ProxyClass.Members.Add(constructor);

            // ----------------------------------------------------------------
            // [KnownType(...), ...]
            // ----------------------------------------------------------------

            // We need to generate a [KnownType] for all derived entities on the visible root.
            if (!this.IsDerivedType)
            {
                // Generate a [KnownType] for every derived type.
                // We specifically exclude [KnownTypes] from the set of attributes we ask
                // the metadata pipeline to generate below, meaning we take total control
                // here for which [KnownType] attributes get through the metadata pipeline.
                //
                // Note, we sort in alphabetic order to give predictability in baselines and
                // client readability.  For cosmetic reasons, we sort by short or long name
                // depending on what our utility helpers will actually generated
                foreach (Type derivedType in derivedTypes.OrderBy(t => this.ClientProxyGenerator.ClientProxyCodeGenerationOptions.UseFullTypeNames ? t.FullName : t.Name))
                {
                    CodeAttributeDeclaration knownTypeAttrib = CodeGenUtilities.CreateAttributeDeclaration(typeof(System.Runtime.Serialization.KnownTypeAttribute), this.ClientProxyGenerator, this.ProxyClass);
                    knownTypeAttrib.Arguments.Add(new CodeAttributeArgument(new CodeTypeOfExpression(CodeGenUtilities.GetTypeReference(derivedType, this.ClientProxyGenerator, this.ProxyClass))));
                    this.ProxyClass.CustomAttributes.Add(knownTypeAttrib);
                }
            }

            this.ValidateTypeAttributes(typeAttributes);

            // ----------------------------------------------------------------
            // [DataContract(Namespace=X, Name=Y)]
            // ----------------------------------------------------------------
            CodeAttributeDeclaration dataContractAttrib = CodeGenUtilities.CreateDataContractAttributeDeclaration(this.Type, this.ClientProxyGenerator, this.ProxyClass);

            this.ProxyClass.CustomAttributes.Add(dataContractAttrib);

            // ----------------------------------------------------------------
            // Propagate all type-level Attributes across (except DataContractAttribute since that is handled above)
            // -----------------------------------------------------------------
            CustomAttributeGenerator.GenerateCustomAttributes(
                this.ClientProxyGenerator,
                this.ProxyClass,
                ex => string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_ThrewException_CodeType, ex.Message, this.ProxyClass.Name, ex.InnerException.Message),
                this.FilterTypeAttributes(typeAttributes),
                this.ProxyClass.CustomAttributes,
                this.ProxyClass.Comments);

            // ----------------------------------------------------------------
            // gen proxy getter/setter for each property
            // ----------------------------------------------------------------
            this.GenerateProperties();

            // ----------------------------------------------------------------
            // gen additional methods/events
            // ----------------------------------------------------------------
            this.GenerateAdditionalMembers();

            // Register created CodeTypeDeclaration with mapping
            this._typeMapping[this.Type] = this.ProxyClass;
        }
        /// <summary>
        /// Generates the client proxy code for a domain service.
        /// </summary>
        public override void Generate()
        {
            // ----------------------------------------------------------------
            // Namespace
            // ----------------------------------------------------------------
            Type                domainServiceType = this._domainServiceDescription.DomainServiceType;
            CodeNamespace       ns         = this.ClientProxyGenerator.GetOrGenNamespace(domainServiceType);
            AttributeCollection attributes = this._domainServiceDescription.Attributes;

            // Missing namespace bails out of code-gen -- error has been logged
            if (ns == null)
            {
                return;
            }

            // ----------------------------------------------------------------
            // public partial sealed class {Name} : DomainContext
            // ----------------------------------------------------------------
            string clientTypeName = DomainContextTypeName(this._domainServiceDescription);

            CodeTypeDeclaration proxyClass = CodeGenUtilities.CreateTypeDeclaration(clientTypeName, domainServiceType.Namespace);

            proxyClass.IsPartial      = true;
            proxyClass.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;
            ns.Types.Add(proxyClass);

            CodeTypeReference domainContextTypeName = CodeGenUtilities.GetTypeReference(TypeConstants.DomainContextTypeFullName, ns.Name, false);

            proxyClass.BaseTypes.Add(domainContextTypeName);

            // Add <summary> xml comment to class
            string comment = string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_DomainContext_Class_Summary_Comment, domainServiceType.Name);

            proxyClass.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment(comment, this.ClientProxyGenerator.IsCSharp));

            // ----------------------------------------------------------------
            // [DomainIdentifier], etc attributes move through metadata pipeline
            // ----------------------------------------------------------------
            CustomAttributeGenerator.GenerateCustomAttributes(
                this.ClientProxyGenerator,
                proxyClass,
                ex => string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_ThrewException_CodeType, ex.Message, proxyClass.Name, ex.InnerException.Message),
                attributes.Cast <Attribute>(),
                proxyClass.CustomAttributes,
                proxyClass.Comments);

            // ----------------------------------------------------------------
            // Add default OnCreated partial method
            // ----------------------------------------------------------------
            NotificationMethodGenerator notificationMethodGen = new NotificationMethodGenerator(this.ClientProxyGenerator);

            proxyClass.Members.AddRange(notificationMethodGen.PartialMethodsSnippetBlock);

            // ----------------------------------------------------------------
            // Generate a contract interface for the service.
            // ----------------------------------------------------------------
            CodeTypeDeclaration contractInterface = this.GenerateContract(proxyClass);

            // ----------------------------------------------------------------
            // Generate constructors
            // ----------------------------------------------------------------
            EnableClientAccessAttribute enableClientAccessAttribute = attributes.OfType <EnableClientAccessAttribute>().Single();

            this.GenerateConstructors(proxyClass, contractInterface, enableClientAccessAttribute, notificationMethodGen.OnCreatedMethodInvokeExpression);

            // ----------------------------------------------------------------
            // Separate proxies for each domain operation entry
            // ----------------------------------------------------------------
            DomainOperationEntryProxyGenerator methodProxyGenerator = new DomainOperationEntryProxyGenerator(this.ClientProxyGenerator, proxyClass, this._domainServiceDescription);

            methodProxyGenerator.Generate();

            // ----------------------------------------------------------------
            // Invoke operations
            // ----------------------------------------------------------------
            InvokeOperationProxyGenerator invokeOperationProxyGenerator = new InvokeOperationProxyGenerator(this.ClientProxyGenerator, proxyClass, this._domainServiceDescription);

            invokeOperationProxyGenerator.Generate();

            // ----------------------------------------------------------------
            // EntityContainer instantiation
            // ----------------------------------------------------------------

            // The entity container holds a collection of EntityLists, one per visible entity root type.
            // The derived entity types are stored in their respective root's list and do not get their own.
            this.GenEntityContainer(proxyClass, this._domainServiceDescription.RootEntityTypes, this._domainServiceDescription);

            // Register created CodeTypeDeclaration with mapping
            this._typeMapping[domainServiceType] = proxyClass;
        }
        //// TODO: we need to refactor this to comply with FxCop
        private CodeTypeDeclaration GenEntityContainerInnerClass(CodeTypeDeclaration proxyClass, IEnumerable <Type> entityTypes, DomainServiceDescription domainServiceDescription)
        {
            // ----------------------------------------------------------------
            // class xxxEntityContainer : EntityContainer
            // ----------------------------------------------------------------
            string containingNamespace = this.ClientProxyGenerator.GetNamespace(proxyClass).Name;
            var    innerClass          = CodeGenUtilities.CreateTypeDeclaration(proxyClass.Name + "EntityContainer", containingNamespace);

            innerClass.BaseTypes.Add(CodeGenUtilities.GetTypeReference(TypeConstants.EntityContainerTypeFullName, containingNamespace, false));
            innerClass.TypeAttributes = TypeAttributes.NotPublic | TypeAttributes.Sealed;
            proxyClass.Members.Add(innerClass);

            // ----------------------------------------------------------------
            // ctor
            // ----------------------------------------------------------------
            var ctor = new CodeConstructor();

            ctor.Attributes = MemberAttributes.Public;
            innerClass.Members.Add(ctor);

            // Convert to a set for faster lookups.
            HashSet <Type> entityTypesToUse = new HashSet <Type>();

            foreach (Type entityType in entityTypes)
            {
                entityTypesToUse.Add(entityType);
            }

            // ----------------------------------------------------------------
            // each entity type gets 'CreateEntitySet<entityType>()' statement in ctor
            // ----------------------------------------------------------------
            foreach (Type entityType in entityTypes.OrderBy(t => t.FullName))
            {
                // Skip entity types which have base classes.
                if (entityTypesToUse.Any(t => t != entityType && t.IsAssignableFrom(entityType)))
                {
                    continue;
                }

                // ----------------------------------------------------------------
                // Build EntitySetOperations enum value
                // ----------------------------------------------------------------
                var            enumTypeReference   = CodeGenUtilities.GetTypeReference(TypeConstants.EntitySetOperationsTypeFullName, containingNamespace, false);
                CodeExpression entitySetOperations = null;

                // Check to see what update operations are supported, and build up the EntitySetOperations flags expression
                bool canInsert = domainServiceDescription.IsOperationSupported(entityType, DomainOperation.Insert);
                bool canEdit   = domainServiceDescription.IsOperationSupported(entityType, DomainOperation.Update);
                bool canDelete = domainServiceDescription.IsOperationSupported(entityType, DomainOperation.Delete);

                CodeTypeReferenceExpression enumTypeReferenceExp = new CodeTypeReferenceExpression(enumTypeReference);

                if (!canInsert && !canEdit && !canDelete)
                {
                    // if no update operations are supported, set to 'None'
                    entitySetOperations = new CodeFieldReferenceExpression(enumTypeReferenceExp, "None");
                }
                else if (canInsert && canEdit && canDelete)
                {
                    // if all operations are supported, set to 'All'
                    entitySetOperations = new CodeFieldReferenceExpression(enumTypeReferenceExp, "All");
                }
                else
                {
                    if (canInsert)
                    {
                        entitySetOperations = new CodeFieldReferenceExpression(enumTypeReferenceExp, "Add");
                    }
                    if (canEdit)
                    {
                        CodeFieldReferenceExpression setOp = new CodeFieldReferenceExpression(enumTypeReferenceExp, "Edit");
                        if (entitySetOperations == null)
                        {
                            entitySetOperations = setOp;
                        }
                        else
                        {
                            entitySetOperations = new CodeBinaryOperatorExpression(entitySetOperations, CodeBinaryOperatorType.BitwiseOr, setOp);
                        }
                    }
                    if (canDelete)
                    {
                        CodeFieldReferenceExpression setOp = new CodeFieldReferenceExpression(enumTypeReferenceExp, "Remove");
                        if (entitySetOperations == null)
                        {
                            entitySetOperations = setOp;
                        }
                        else
                        {
                            entitySetOperations = new CodeBinaryOperatorExpression(entitySetOperations, CodeBinaryOperatorType.BitwiseOr, setOp);
                        }
                    }
                }


                // ----------------------------------------------------------------
                // method call: this.CreateEntitySet<entityType>
                // ----------------------------------------------------------------
                var entityTypeReference = CodeGenUtilities.GetTypeReference(entityType, this.ClientProxyGenerator, proxyClass);
                var methodRef           = new CodeMethodReferenceExpression(new CodeThisReferenceExpression(), "CreateEntitySet", entityTypeReference);
                var methodCall          = new CodeMethodInvokeExpression(methodRef, entitySetOperations);
                ctor.Statements.Add(methodCall);
            }

            return(innerClass);
        }
Exemple #5
0
        public override void Generate()
        {
            // ----------------------------------------------------------------
            // namespace
            // ----------------------------------------------------------------
            CodeNamespace ns = this.ClientProxyGenerator.GetOrGenNamespace(this.ClientProxyGenerator.ClientProxyCodeGenerationOptions.ClientRootNamespace);

            // Missing namespace bails out of code-gen -- error has been logged
            if (ns == null)
            {
                return;
            }

            // Log an informational message to help users see progress
            this.ClientProxyGenerator.LogMessage(Resource.CodeGen_Generating_WebContext);

            // Find the AuthenticationServices and if there's just one, use it as the default.
            IEnumerable <DomainServiceDescription> authDescriptions =
                this.ClientProxyGenerator.DomainServiceDescriptions.Where(d => typeof(IAuthentication <>).DefinitionIsAssignableFrom(d.DomainServiceType));
            DomainServiceDescription defaultAuthDescription = null;

            if (authDescriptions.Count() > 1)
            {
                this.ClientProxyGenerator.LogMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        Resource.WebContext_ManyAuthServices,
                        string.Join(",", authDescriptions.Select(d => d.DomainServiceType.Name).ToArray())));
            }
            else
            {
                defaultAuthDescription = authDescriptions.FirstOrDefault();
            }

            // ----------------------------------------------------------------
            // public partial sealed class WebContext : WebContextBase
            // ----------------------------------------------------------------
            CodeTypeDeclaration proxyClass = CodeGenUtilities.CreateTypeDeclaration("WebContext", ns.Name);

            proxyClass.IsPartial      = true;
            proxyClass.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;
            proxyClass.BaseTypes.Add(CodeGenUtilities.GetTypeReference(TypeConstants.WebContextBaseName, ns.Name, false));
            proxyClass.Comments.AddRange(CodeGenUtilities.GetDocComments(Resource.WebContext_CommentClass, this.ClientProxyGenerator.IsCSharp));

            ns.Types.Add(proxyClass);

            // ----------------------------------------------------------------
            // public WebContext()
            // {
            //     <!-- if there's a default authentication service
            //     this.Authentication = new WebUserService();
            //     -->
            //     this.OnCreated();
            // }
            // ----------------------------------------------------------------
            CodeConstructor constructor = new CodeConstructor();

            constructor.Attributes = MemberAttributes.Public;
            //if (defaultAuthDescription != null)
            //{
            //    // TODO: Choose between Forms and Windows when reading from web.config is available
            //    //constructor.Statements.Add(
            //    //    new CodeAssignStatement(
            //    //        new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "Authentication"),
            //    //        new CodeObjectCreateExpression(WebContextGenerator.FormsAuthenticationName)));
            //}
            NotificationMethodGenerator onCreatedMethodGenerator = new NotificationMethodGenerator(
                this.ClientProxyGenerator,
                this.ClientProxyGenerator.IsCSharp ? IndentationLevel.Namespace : IndentationLevel.GlobalNamespace);

            constructor.Statements.Add(onCreatedMethodGenerator.OnCreatedMethodInvokeExpression);
            constructor.Comments.AddRange(CodeGenUtilities.GetDocComments(Resource.WebContext_CommentConstructor, this.ClientProxyGenerator.IsCSharp));

            proxyClass.Members.Add(constructor);

            // ----------------------------------------------------------------
            // #region Extensibility Method Definitions
            // partial void OnCreated();
            // #endregion
            // ----------------------------------------------------------------
            proxyClass.Members.AddRange(onCreatedMethodGenerator.PartialMethodsSnippetBlock);

            // ----------------------------------------------------------------
            // public static new WebContext Current
            // {
            //     get { return (WebContext)WebContextBase.Current; }
            // }
            // ----------------------------------------------------------------
            CodeMemberProperty          currentProperty = new CodeMemberProperty();
            string                      typeFullName    = (string.IsNullOrEmpty(ns.Name) ? string.Empty : ns.Name + ".") + "WebContext";
            CodeTypeReference           targetTypeRef   = CodeGenUtilities.GetTypeReference(typeFullName, ns.Name, true);
            CodeTypeReference           baseTypeRef     = CodeGenUtilities.GetTypeReference(TypeConstants.WebContextBaseName, ns.Name, false);
            CodeTypeReferenceExpression baseTypeRefExp  = new CodeTypeReferenceExpression(baseTypeRef);

            currentProperty.Attributes = MemberAttributes.Public | MemberAttributes.Static | MemberAttributes.New;
            currentProperty.Type       = targetTypeRef;
            currentProperty.Name       = "Current";
            currentProperty.HasGet     = true;
            currentProperty.GetStatements.Add(
                new CodeMethodReturnStatement(
                    new CodeCastExpression(currentProperty.Type,
                                           new CodePropertyReferenceExpression(baseTypeRefExp, "Current"))));
            currentProperty.Comments.AddRange(CodeGenUtilities.GetDocComments(Resource.WebContext_CommentCurrent, this.ClientProxyGenerator.IsCSharp));

            proxyClass.Members.Add(currentProperty);

            // ----------------------------------------------------------------
            // <!-- if there's a default authentication service
            // public new MyUser User
            // {
            //     get { return (MyUser)base.User; }
            // }
            // -->
            // ----------------------------------------------------------------
            if (defaultAuthDescription != null)
            {
                Type genericType = null;
                typeof(IAuthentication <>).DefinitionIsAssignableFrom(defaultAuthDescription.DomainServiceType, out genericType);
                if ((genericType != null) && (genericType.GetGenericArguments().Count() == 1))
                {
                    CodeMemberProperty userProperty = new CodeMemberProperty();

                    userProperty.Attributes = MemberAttributes.Public | MemberAttributes.New | MemberAttributes.Final;
                    userProperty.Type       = CodeGenUtilities.GetTypeReference(
                        genericType.GetGenericArguments()[0], this.ClientProxyGenerator, proxyClass);
                    userProperty.Name   = "User";
                    userProperty.HasGet = true;
                    userProperty.GetStatements.Add(
                        new CodeMethodReturnStatement(
                            new CodeCastExpression(userProperty.Type,
                                                   new CodePropertyReferenceExpression(
                                                       new CodeBaseReferenceExpression(),
                                                       "User"))));
                    userProperty.Comments.AddRange(CodeGenUtilities.GetDocComments(Resource.WebContext_CommentUser, this.ClientProxyGenerator.IsCSharp));

                    proxyClass.Members.Add(userProperty);
                }
            }
        }
Exemple #6
0
        /// <summary>
        /// Creates a new <see cref="CodeTypeDeclaration"/> that is the generated form of
        /// the given <paramref name="enumType"/>.
        /// </summary>
        /// <param name="enumType">The enum type to generate.</param>
        /// <param name="codeGenerator">The current proxy generator context.</param>
        /// <returns>The newly generated enum type declaration.</returns>
        internal static CodeTypeDeclaration CreateEnumTypeDeclaration(Type enumType, CodeDomClientCodeGenerator codeGenerator)
        {
            System.Diagnostics.Debug.Assert(enumType.IsEnum, "Type must be an enum type");

            CodeTypeDeclaration typeDecl = CodeGenUtilities.CreateTypeDeclaration(enumType);

            typeDecl.IsEnum = true;

            // Always force generated enums to be public
            typeDecl.TypeAttributes |= TypeAttributes.Public;

            // Enums deriving from anything but int get an explicit base type
            Type underlyingType = enumType.GetEnumUnderlyingType();

            if (underlyingType != typeof(int))
            {
                typeDecl.BaseTypes.Add(new CodeTypeReference(underlyingType));
            }

            typeDecl.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment($"Enum {enumType.Name}", codeGenerator.IsCSharp));

            // Generate [DataContract] if it appears in the original only.  Use Reflection only because that matches
            // what WCF will do.
            DataContractAttribute dataContractAttr = (DataContractAttribute)Attribute.GetCustomAttribute(enumType, typeof(DataContractAttribute));

            if (dataContractAttr != null)
            {
                CodeAttributeDeclaration attrDecl = CodeGenUtilities.CreateDataContractAttributeDeclaration(enumType, codeGenerator, typeDecl);
                typeDecl.CustomAttributes.Add(attrDecl);
            }

            string[] memberNames   = Enum.GetNames(enumType);
            Type     enumValueType = Enum.GetUnderlyingType(enumType);

            for (int i = 0; i < memberNames.Length; ++i)
            {
                string            memberName  = memberNames[i];
                CodeTypeReference enumTypeRef = CodeGenUtilities.GetTypeReference(enumValueType, codeGenerator, typeDecl);
                CodeMemberField   enumMember  = new CodeMemberField(enumTypeRef, memberName);

                enumMember.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment(memberName, codeGenerator.IsCSharp));

                // Generate an initializer for the enum member.
                // GetRawConstantValue is the safest way to get the raw value of the enum field
                // and works for both Reflection and ReflectionOnly loaded assemblies.
                FieldInfo fieldInfo = enumType.GetField(memberName);
                if (fieldInfo != null)
                {
                    object memberValue = fieldInfo.GetRawConstantValue();

                    Debug.Assert(memberValue != null, "Enum type's GetRawConstantValue should never return null");

                    // We special-case MinValue and MaxValue for the integral types
                    // because VisualBasic will generate overflow compiler error for
                    // Int64.MinValue.   If we detect a known MinValue or MaxValue for
                    // this integral type, we generate that reference, otherwise we
                    // just generate a constant integral value of the enum's type
                    object[] minMaxValues = null;
                    CodeGenUtilities.integralMinMaxValues.TryGetValue(underlyingType, out minMaxValues);
                    Debug.Assert(minMaxValues == null || minMaxValues.Length == 3, "integralMinMaxValues elements must always contain 3 values");

                    // Gen xxx.MinValue if it matches, but give precedence to matching a true zero,
                    // which is the min value for the unsigned integral types
                    // minMaxValues[0]: the MinValue for this type
                    // minMaxValues[1]: the MaxValue for this type
                    // minMaxValues[2]: the zero for this type (memberValue is not boxed and cannot be cast)
                    if (minMaxValues != null && !memberValue.Equals(minMaxValues[2]) && memberValue.Equals(minMaxValues[0]))
                    {
                        enumMember.InitExpression = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(underlyingType), "MinValue");
                    }
                    // Gen xxx.MaxValue if it matches
                    else if (minMaxValues != null && memberValue.Equals(minMaxValues[1]))
                    {
                        enumMember.InitExpression = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(underlyingType), "MaxValue");
                    }
                    // All other cases generate an integral constant.
                    // CodeDom knows how to generate the right integral constant based on memberValue's type.
                    else
                    {
                        enumMember.InitExpression = new CodePrimitiveExpression(memberValue);
                    }
                }

                typeDecl.Members.Add(enumMember);

                // Generate an [EnumMember] if appropriate
                EnumMemberAttribute enumMemberAttr = (EnumMemberAttribute)Attribute.GetCustomAttribute(fieldInfo, typeof(EnumMemberAttribute));
                if (enumMemberAttr != null)
                {
                    CodeAttributeDeclaration enumAttrDecl = CodeGenUtilities.CreateEnumMemberAttributeDeclaration(fieldInfo, codeGenerator, typeDecl);
                    enumMember.CustomAttributes.Add(enumAttrDecl);
                }

                // Propagate any other attributes that can be seen by the client
                CustomAttributeGenerator.GenerateCustomAttributes(
                    codeGenerator,
                    typeDecl,
                    ex => string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_ThrewException_CodeTypeMember, ex.Message, fieldInfo.Name, typeDecl.Name, ex.InnerException.Message),
                    fieldInfo.GetCustomAttributes(false).Cast <Attribute>().Where(a => a.GetType() != typeof(EnumMemberAttribute)),
                    enumMember.CustomAttributes,
                    enumMember.Comments);
            }

            // Attributes marked with [Flag] propagate it
            if (enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0)
            {
                CodeAttributeDeclaration attrDecl = CodeGenUtilities.CreateAttributeDeclaration(typeof(FlagsAttribute), codeGenerator, typeDecl);
                typeDecl.CustomAttributes.Add(attrDecl);
            }
            return(typeDecl);
        }