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