Example #1
0
        /// <summary>
        /// Creates a <see cref="CodeAttributeDeclaration"/> for a <see cref="DataContractAttribute"/>
        /// </summary>
        /// <param name="sourceType">The type to which the attribute will be applied (to use as a reference)</param>
        /// <param name="codeGenerator">The client proxy generator</param>
        /// <param name="referencingType">The type referencing this declaration</param>
        /// <returns>The new attribute declaration</returns>
        internal static CodeAttributeDeclaration CreateDataContractAttributeDeclaration(Type sourceType, CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType)
        {
            CodeAttributeDeclaration dataContractAttrib = CodeGenUtilities.CreateAttributeDeclaration(typeof(System.Runtime.Serialization.DataContractAttribute), codeGenerator, referencingType);

            string dataContractNamespace = CodeGenUtilities.GetContractNamespace(sourceType);
            string dataContractName      = null;

            // If the user specified a DataContract, we should copy the namespace and name.
            DataContractAttribute sourceDataContractAttrib = (DataContractAttribute)Attribute.GetCustomAttribute(sourceType, typeof(DataContractAttribute));

            if (sourceDataContractAttrib != null)
            {
                if (sourceDataContractAttrib.Namespace != null)
                {
                    dataContractNamespace = sourceDataContractAttrib.Namespace;
                }
                if (sourceDataContractAttrib.Name != null)
                {
                    dataContractName = sourceDataContractAttrib.Name;
                }
            }

            dataContractAttrib.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(dataContractNamespace)));
            if (dataContractName != null)
            {
                dataContractAttrib.Arguments.Add(new CodeAttributeArgument("Name", new CodePrimitiveExpression(dataContractName)));
            }
            return(dataContractAttrib);
        }
        private void GenerateContractMethodAttributes(CodeTypeDeclaration contractInterface, CodeMemberMethod beginQueryMethod, string domainServiceName, string operationName)
        {
            CodeAttributeDeclaration operationContractAtt = CodeGenUtilities.CreateAttributeDeclaration(typeof(OperationContractAttribute), this.ClientProxyGenerator, contractInterface);

            operationContractAtt.Arguments.Add(new CodeAttributeArgument("AsyncPattern", new CodePrimitiveExpression(true)));
            operationContractAtt.Arguments.Add(new CodeAttributeArgument("Action", new CodePrimitiveExpression(string.Format(CultureInfo.InvariantCulture, DomainServiceProxyGenerator.DefaultActionSchema, domainServiceName, operationName))));
            operationContractAtt.Arguments.Add(new CodeAttributeArgument("ReplyAction", new CodePrimitiveExpression(string.Format(CultureInfo.InvariantCulture, DomainServiceProxyGenerator.DefaultReplyActionSchema, domainServiceName, operationName))));
            beginQueryMethod.CustomAttributes.Add(operationContractAtt);
        }
Example #3
0
        /// <summary>
        /// Creates a <see cref="CodeAttributeDeclaration"/> for a <see cref="DisplayAttribute"/>.
        /// </summary>
        /// <param name="codeGenerator">The client proxy generator</param>
        /// <param name="referencingType">The type on whose member <see cref="DisplayAttribute"/> will be applied</param>
        /// <returns>The new attribute declaration</returns>
        internal static CodeAttributeDeclaration CreateDisplayAttributeDeclaration(CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType)
        {
            CodeAttributeDeclaration displayAttributeDeclaration = CodeGenUtilities.CreateAttributeDeclaration(
                typeof(DisplayAttribute),
                codeGenerator,
                referencingType);

            displayAttributeDeclaration.Arguments.Add(new CodeAttributeArgument("AutoGenerateField", new CodePrimitiveExpression(false)));

            return(displayAttributeDeclaration);
        }
        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);
        }
Example #5
0
        /// <summary>
        /// Creates an attribute declaration for <see cref="EnumMemberAttribute"/>
        /// </summary>
        /// <param name="memberInfo">The member that may contain an existing <see cref="EnumMemberAttribute"/></param>
        /// <param name="codeGenerator">The proxy generator</param>
        /// <param name="referencingType">The referencing type</param>
        /// <returns>A new attribute declaration</returns>
        internal static CodeAttributeDeclaration CreateEnumMemberAttributeDeclaration(MemberInfo memberInfo, CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType)
        {
            CodeAttributeDeclaration enumMemberDecl = CodeGenUtilities.CreateAttributeDeclaration(typeof(System.Runtime.Serialization.EnumMemberAttribute), codeGenerator, referencingType);

            // If the user specified a DataContract, we should copy the namespace and name.
            EnumMemberAttribute enumMemberAttrib = (EnumMemberAttribute)Attribute.GetCustomAttribute(memberInfo, typeof(EnumMemberAttribute));

            if (enumMemberAttrib != null)
            {
                string value = enumMemberAttrib.Value;
                if (!string.IsNullOrEmpty(value))
                {
                    enumMemberDecl.Arguments.Add(new CodeAttributeArgument("Value", new CodePrimitiveExpression(value)));
                }
            }
            return(enumMemberDecl);
        }
        /// <summary>
        /// Creates a <see cref="CodeAttributeDeclaration"/> for the given <see cref="AttributeDeclaration"/>.
        /// </summary>
        /// <param name="proxyGenerator">The context for generating code.  It cannot be null.</param>
        /// <param name="referencingType">The referencing type.</param>
        /// <param name="attributeDeclaration">The <see cref="AttributeDeclaration"/> to build.</param>
        /// <returns>A <see cref="CodeAttributeDeclaration"/>.</returns>
        private static CodeAttributeDeclaration CreateCodeAttributeDeclaration(CodeDomClientCodeGenerator proxyGenerator, CodeTypeDeclaration referencingType, AttributeDeclaration attributeDeclaration)
        {
            CodeAttributeDeclaration codeAttributeDeclaration = CodeGenUtilities.CreateAttributeDeclaration(attributeDeclaration.AttributeType, proxyGenerator, referencingType);

            // Add ctor args
            foreach (object arg in attributeDeclaration.ConstructorArguments)
            {
                CodeExpression expression = CreateCodeExpression(proxyGenerator, referencingType, arg);
                codeAttributeDeclaration.Arguments.Add(new CodeAttributeArgument(expression));
            }

            // Add named params
            foreach (KeyValuePair <string, object> pair in attributeDeclaration.NamedParameters)
            {
                CodeExpression expression = CreateCodeExpression(proxyGenerator, referencingType, pair.Value);
                codeAttributeDeclaration.Arguments.Add(new CodeAttributeArgument(pair.Key, expression));
            }

            return(codeAttributeDeclaration);
        }
        /// <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 a property getter/setter pair into the given proxy class to match the given property info.
        /// </summary>
        /// <param name="propertyDescriptor">PropertyDescriptor for the property to generate for.</param>
        protected virtual void GenerateProperty(PropertyDescriptor propertyDescriptor)
        {
            string propertyName = propertyDescriptor.Name;
            Type   propertyType = CodeGenUtilities.TranslateType(propertyDescriptor.PropertyType);

            // ----------------------------------------------------------------
            // Property type ref
            // ----------------------------------------------------------------
            var propTypeReference = CodeGenUtilities.GetTypeReference(propertyType, this.ClientProxyGenerator, this.ProxyClass);

            // ----------------------------------------------------------------
            // Property decl
            // ----------------------------------------------------------------
            var property = new CodeMemberProperty();

            property.Name       = propertyName;
            property.Type       = propTypeReference;
            property.Attributes = MemberAttributes.Public | MemberAttributes.Final; // final needed, else becomes virtual
            List <Attribute> propertyAttributes = propertyDescriptor.ExplicitAttributes().Cast <Attribute>().ToList();

            // Generate <summary> for property
            string comment = string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_Entity_Property_Summary_Comment, propertyName);

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

            // ----------------------------------------------------------------
            // [DataMember] -> Add if not already present.
            // ----------------------------------------------------------------
            // Add if not already present.

            if (!propertyAttributes.OfType <DataMemberAttribute>().Any())
            {
                CodeAttributeDeclaration dataMemberAtt = CodeGenUtilities.CreateAttributeDeclaration(typeof(DataMemberAttribute), this.ClientProxyGenerator, this.ProxyClass);
                property.CustomAttributes.Add(dataMemberAtt);
            }

            // Here, we check for the existence of [ReadOnly(true)] attributes generated when
            // the property does not not have a setter.  We want to inject an [Editable(false)]
            // attribute into the pipeline.
            ReadOnlyAttribute readOnlyAttr = propertyAttributes.OfType <ReadOnlyAttribute>().SingleOrDefault();

            if (readOnlyAttr != null && !propertyAttributes.OfType <EditableAttribute>().Any())
            {
                propertyAttributes.Add(new EditableAttribute(!readOnlyAttr.IsReadOnly));

                // REVIEW:  should we strip out [ReadOnly] attributes here?
            }

            // Here we check if the type has a RoundtripOriginalAttribute. In that case we strip it out from the property
            if (this._isRoundtripType)
            {
                propertyAttributes.RemoveAll(attr => attr.GetType() == typeof(RoundtripOriginalAttribute));
            }

            // Here we check for database generated fields. In that case we strip any RequiredAttribute from the property.
            if (propertyAttributes.Any(a => a.GetType().Name == "DatabaseGeneratedAttribute"))
            {
                propertyAttributes.RemoveAll(attr => attr.GetType() == typeof(RequiredAttribute));
            }

            // Here, we check for the presence of a complex type. If it exists we need to add a DisplayAttribute
            // if not already there. DataSources windows do not handle complex types
            if (TypeUtility.IsSupportedComplexType(propertyType) && !propertyAttributes.OfType <DisplayAttribute>().Any())
            {
                CodeAttributeDeclaration displayAttribute = CodeGenUtilities.CreateDisplayAttributeDeclaration(this.ClientProxyGenerator, this.ProxyClass);
                property.CustomAttributes.Add(displayAttribute);
            }

            // ----------------------------------------------------------------
            // Propagate the custom attributes
            // ----------------------------------------------------------------

            CustomAttributeGenerator.GenerateCustomAttributes(
                this.ClientProxyGenerator,
                this.ProxyClass,
                ex => string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_ThrewException_CodeTypeMember, ex.Message, property.Name, this.ProxyClass.Name, ex.InnerException.Message),
                propertyAttributes.Cast <Attribute>(),
                property.CustomAttributes,
                property.Comments);

            // ----------------------------------------------------------------
            // backing private field (CodeDom doesn't yet know about auto properties)
            // ----------------------------------------------------------------
            string fieldName = CodeGenUtilities.MakeCompliantFieldName(propertyName);
            var    field     = new CodeMemberField(propTypeReference, fieldName);

            this.ProxyClass.Members.Add(field);
            var fieldRef = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName);
            var valueRef = new CodePropertySetValueReferenceExpression();

            // ----------------------------------------------------------------
            // getter body
            // ----------------------------------------------------------------
            property.GetStatements.Add(new CodeMethodReturnStatement(fieldRef));

            // ----------------------------------------------------------------
            // setter body
            // ----------------------------------------------------------------
            List <CodeStatement> bodyStatements = new List <CodeStatement>();

            // this.OnPropertyXxxChanging(PropType value);
            bodyStatements.Add(this.NotificationMethodGen.GetMethodInvokeExpressionStatementFor(propertyName + "Changing"));

            bool propertyIsReadOnly = this.IsPropertyReadOnly(propertyDescriptor);

            if (!propertyIsReadOnly)
            {
                bodyStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "RaiseDataMemberChanging", new CodePrimitiveExpression(propertyDescriptor.Name))));
            }

            // Generate the validation tests.
            CodeStatement validationCode = GeneratePropertySetterValidation(propertyDescriptor.Name);

            bodyStatements.Add(validationCode);

            // this._field = value
            bodyStatements.Add(new CodeAssignStatement(fieldRef, valueRef));

            if (!propertyIsReadOnly)
            {
                bodyStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "RaiseDataMemberChanged", new CodePrimitiveExpression(propertyDescriptor.Name))));
            }
            else
            {
                // even read-only members need to raise PropertyChanged
                bodyStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "RaisePropertyChanged", new CodePrimitiveExpression(propertyDescriptor.Name))));
            }

            // this.OnPropertyXxxChanged();
            bodyStatements.Add(this.NotificationMethodGen.GetMethodInvokeExpressionStatementFor(propertyName + "Changed"));

            // if (this._field != value)...
            CodeExpression valueTest = CodeGenUtilities.MakeNotEqual(propertyType, fieldRef, valueRef, this.ClientProxyGenerator.IsCSharp);

            CodeConditionStatement body = new CodeConditionStatement(valueTest, bodyStatements.ToArray <CodeStatement>());

            property.SetStatements.Add(body);

            // add property
            this.ProxyClass.Members.Add(property);
        }
Example #9
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);
        }