private void GenerateConfigurationSectionCode(ConfigurationElement element, CodeTypeDeclaration elementClass) { ConfigurationSection configurationSectionElement = (ConfigurationSection)element; string sectionName = string.Format("{0}SectionName", element.Name); string FQElementName = string.Format("{0}.{1}", element.ActualNamespace, element.Name); if ((configurationSectionElement.CodeGenOptions & ConfigurationSectionCodeGenOptions.Singleton) == ConfigurationSectionCodeGenOptions.Singleton) { MemberAttributes doShadowing = 0; IEnumerable <BaseConfigurationType> ancestors; configurationSectionElement.GetAncestors(out ancestors); foreach (BaseConfigurationType ancestor in ancestors) { if (ancestor == configurationSectionElement) { continue; } ConfigurationSection ancestorSection = (ConfigurationSection)ancestor; if ((ancestorSection.CodeGenOptions & ConfigurationSectionCodeGenOptions.Singleton) == ConfigurationSectionCodeGenOptions.Singleton) { doShadowing = MemberAttributes.New; break; } } // Add XML section name CodeMemberField sectionXmlNameField = new CodeMemberField(_string, sectionName); elementClass.Members.Add(sectionXmlNameField); sectionXmlNameField.StartDirectives.Add(Region("Singleton Instance")); sectionXmlNameField.Comments.Add(DocComment("<summary>")); sectionXmlNameField.Comments.Add(DocComment(string.Format("The XML name of the {0} Configuration Section.", element.Name))); sectionXmlNameField.Comments.Add(DocComment("</summary>")); sectionXmlNameField.CustomAttributes.Add(_generatedCodeAttribute); sectionXmlNameField.Attributes = MemberAttributes.Assembly | MemberAttributes.Const; sectionXmlNameField.InitExpression = new CodePrimitiveExpression(configurationSectionElement.XmlSectionName); /**/ // UPDATE 20140910: Developed function to support nested groups based on recommendation from WI 6053 Patch: // Add Configuration Section Path string sectionPath = string.Format("{0}SectionPath", element.Name); CodeMemberField sectionPathField = new CodeMemberField(_string, sectionPath); elementClass.Members.Add(sectionPathField); sectionPathField.Comments.Add(DocComment("<summary>")); sectionPathField.Comments.Add(DocComment(string.Format("The XML path of the {0} Configuration Section.", element.Name))); sectionPathField.Comments.Add(DocComment("</summary>")); sectionPathField.CustomAttributes.Add(_generatedCodeAttribute); sectionPathField.Attributes = MemberAttributes.Assembly | MemberAttributes.Const; if (configurationSectionElement.ReferringConfigurationSectionGroup != null && !string.IsNullOrEmpty(configurationSectionElement.ReferringConfigurationSectionGroup.ConfigurationSectionGroup.Name)) { // TODO 20140910: Very limited testing so far. _NestedGroupHelper(element, configurationSectionElement, ref elementClass, ref sectionPathField); } else { // Configuration Section Path Value sectionPathField.InitExpression = new CodePrimitiveExpression(configurationSectionElement.XmlSectionName); } /* */ // TODO: Code generators should handle errors nicely. Was hard to see an error occured when there was a bug in block above. Currently, // the generator simply appears to hang or stop running without any notice. // Add Instance property. CodeMemberProperty instanceProperty = new CodeMemberProperty(); elementClass.Members.Add(instanceProperty); instanceProperty.Comments.Add(DocComment("<summary>")); instanceProperty.Comments.Add(DocComment(string.Format("Gets the {0} instance.", element.Name))); instanceProperty.Comments.Add(DocComment("</summary>")); instanceProperty.CustomAttributes.Add(_generatedCodeAttribute); instanceProperty.Attributes = doShadowing | MemberAttributes.Public | MemberAttributes.Static; instanceProperty.Type = GlobalSelfReference(element.FullName); instanceProperty.Name = "Instance"; instanceProperty.HasGet = true; instanceProperty.GetStatements.Add( new CodeMethodReturnStatement( new CodeCastExpression( GlobalSelfReference(element.FullName), new CodeMethodInvokeExpression( GlobalReferenceExpression(typeof(System.Configuration.ConfigurationManager)), "GetSection", new CodeFieldReferenceExpression( GlobalSelfReferenceExpression(FQElementName), sectionPath // Changed from sectionName to support groups. ) ) ) ) ); instanceProperty.EndDirectives.Add(EndRegion()); } if ((configurationSectionElement.CodeGenOptions & ConfigurationSectionCodeGenOptions.XmlnsProperty) == ConfigurationSectionCodeGenOptions.XmlnsProperty) { // Add Xmlns Property Name field. CodeMemberField xmlnsNameField = new CodeMemberField(_string, "XmlnsPropertyName"); elementClass.Members.Add(xmlnsNameField); xmlnsNameField.StartDirectives.Add(Region("Xmlns Property")); xmlnsNameField.Comments.Add(DocComment("<summary>")); xmlnsNameField.Comments.Add(DocComment("The XML name of the <see cref=\"Xmlns\"/> property.")); xmlnsNameField.Comments.Add(DocComment("</summary>")); xmlnsNameField.CustomAttributes.Add(_generatedCodeAttribute); xmlnsNameField.Attributes = MemberAttributes.Assembly | MemberAttributes.Const; xmlnsNameField.InitExpression = new CodePrimitiveExpression("xmlns"); // Add Xmlns property. CodeMemberProperty xmlnsProperty = new CodeMemberProperty(); elementClass.Members.Add(xmlnsProperty); xmlnsProperty.Comments.Add(DocComment("<summary>")); xmlnsProperty.Comments.Add(DocComment("Gets the XML namespace of this Configuration Section.")); xmlnsProperty.Comments.Add(DocComment("</summary>")); xmlnsProperty.Comments.Add(DocComment("<remarks>")); xmlnsProperty.Comments.Add(DocComment("This property makes sure that if the configuration file contains the XML namespace,")); xmlnsProperty.Comments.Add(DocComment("the parser doesn't throw an exception because it encounters the unknown \"xmlns\" attribute.")); xmlnsProperty.Comments.Add(DocComment("</remarks>")); xmlnsProperty.CustomAttributes.Add(_generatedCodeAttribute); CodeAttributeDeclaration configPropertyAttribute = new CodeAttributeDeclaration(GlobalReference(typeof(System.Configuration.ConfigurationPropertyAttribute)), new CodeAttributeArgument(new CodeFieldReferenceExpression(GlobalSelfReferenceExpression(FQElementName), "XmlnsPropertyName")), new CodeAttributeArgument("IsRequired", new CodePrimitiveExpression(false)), new CodeAttributeArgument("IsKey", new CodePrimitiveExpression(false)), new CodeAttributeArgument("IsDefaultCollection", new CodePrimitiveExpression(false))); xmlnsProperty.CustomAttributes.Add(configPropertyAttribute); xmlnsProperty.Attributes = MemberAttributes.Public | MemberAttributes.Final; xmlnsProperty.Type = _string; xmlnsProperty.Name = "Xmlns"; xmlnsProperty.HasGet = true; xmlnsProperty.GetStatements.Add( new CodeMethodReturnStatement( new CodeCastExpression( _string, new CodeIndexerExpression( _base, new CodeFieldReferenceExpression( GlobalSelfReferenceExpression(FQElementName), xmlnsNameField.Name ) ) ) ) ); xmlnsProperty.EndDirectives.Add(EndRegion()); } if ((configurationSectionElement.CodeGenOptions & ConfigurationSectionCodeGenOptions.Protection) == ConfigurationSectionCodeGenOptions.Protection) { // Add Protection Provider field CodeMemberField protectionProviderField = new CodeMemberField(_string, "ProtectionProvider"); elementClass.Members.Add(protectionProviderField); protectionProviderField.StartDirectives.Add(Region("Protection")); protectionProviderField.Comments.Add(DocComment("<summary>")); protectionProviderField.Comments.Add(DocComment("The protection provider to use for Configuration Section Protection")); protectionProviderField.Comments.Add(DocComment("</summary>")); protectionProviderField.CustomAttributes.Add(_generatedCodeAttribute); protectionProviderField.Attributes = MemberAttributes.Assembly | MemberAttributes.Const; if (configurationSectionElement.ProtectionProvider == ProtectionProviders.DataProtectionConfigurationProvider) { protectionProviderField.InitExpression = new CodePrimitiveExpression("DataProtectionConfigurationProvider"); } else if (configurationSectionElement.ProtectionProvider == ProtectionProviders.RSAProtectedConfigurationProvider) { protectionProviderField.InitExpression = new CodePrimitiveExpression("RSAProtectedConfigurationProvider"); } else { protectionProviderField.InitExpression = new CodePrimitiveExpression(configurationSectionElement.CustomProtectionProvider); } // Add Protect method CodeMemberMethod protectMethod = new CodeMemberMethod(); elementClass.Members.Add(protectMethod); protectMethod.Comments.Add(DocComment("<summary>")); protectMethod.Comments.Add(DocComment("Marks this Configuration Section for protection.")); protectMethod.Comments.Add(DocComment("</summary>")); protectMethod.CustomAttributes.Add(_generatedCodeAttribute); protectMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; protectMethod.ReturnType = _void; protectMethod.Name = "Protect"; protectMethod.Statements.Add( new CodeConditionStatement( new CodeBinaryOperatorExpression( new CodeFieldReferenceExpression( new CodeFieldReferenceExpression(_this, "SectionInformation"), "IsProtected" ), CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false) ), new CodeExpressionStatement( new CodeMethodInvokeExpression( new CodeFieldReferenceExpression(_this, "SectionInformation"), "ProtectSection", new CodeFieldReferenceExpression( GlobalSelfReferenceExpression(FQElementName), protectionProviderField.Name ) ) ) ) ); // Add Unprotect method CodeMemberMethod unprotectMethod = new CodeMemberMethod(); elementClass.Members.Add(unprotectMethod); unprotectMethod.Comments.Add(DocComment("<summary>")); unprotectMethod.Comments.Add(DocComment("Removes the protected configuration encryption from the associated configuration section.")); unprotectMethod.Comments.Add(DocComment("</summary>")); unprotectMethod.CustomAttributes.Add(_generatedCodeAttribute); unprotectMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; unprotectMethod.ReturnType = _void; unprotectMethod.Name = "Unprotect"; unprotectMethod.Statements.Add( new CodeConditionStatement( new CodeBinaryOperatorExpression( new CodeFieldReferenceExpression( new CodeFieldReferenceExpression(_this, "SectionInformation"), "IsProtected" ), CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(true) ), new CodeExpressionStatement( new CodeMethodInvokeExpression( new CodeFieldReferenceExpression(_this, "SectionInformation"), "UnprotectSection" ) ) ) ); unprotectMethod.EndDirectives.Add(EndRegion()); } }
private void GenerateConfigurationElementCollectionCode(ConfigurationElement element, CodeTypeDeclaration elementClass) { ConfigurationElementCollection collectionElement = (ConfigurationElementCollection)element; ConfigurationProperty keyProperty = null; if (collectionElement.ItemType.KeyProperties.Count == 1) { keyProperty = collectionElement.ItemType.KeyProperties.Single(); } string xmlPropertyName = string.Format("{0}PropertyName", collectionElement.ItemType.Name); string configurationElementTypeReference = GetTypeReferenceString(typeof(System.Configuration.ConfigurationElement)); string configurationElementCollectionTypeReference = GetTypeReferenceString(typeof(System.Configuration.ConfigurationElementCollection)); CodeTypeReference collectionItemType = GlobalSelfReference(collectionElement.ItemType.FullName); string collectionItemTypeReference = GetTypeSelfReferenceString(collectionElement.ItemType.FullName); CodeTypeReference icollectionTypeReference = null; if ((collectionElement.CodeGenOptions & ConfigurationElementCollectionCodeGenOptions.ICollection) == ConfigurationElementCollectionCodeGenOptions.ICollection) { icollectionTypeReference = new CodeTypeReference(string.Concat("global::System.Collections.Generic.ICollection<", collectionItemTypeReference, ">")); elementClass.BaseTypes.Add(icollectionTypeReference); } // Add ConfigurationCollectionAttribute CodeAttributeDeclaration collectionType = new CodeAttributeDeclaration( GlobalReference(typeof(System.Configuration.ConfigurationCollectionAttribute)), new CodeAttributeArgument(_selftypeof(collectionElement.ItemType.FullName)), new CodeAttributeArgument("CollectionType", new CodeFieldReferenceExpression( GlobalReferenceExpression(collectionElement.CollectionType.GetType()), Enum.GetName(collectionElement.CollectionType.GetType(), collectionElement.CollectionType) ) ) ); if (collectionElement.CollectionType == System.Configuration.ConfigurationElementCollectionType.BasicMap || collectionElement.CollectionType == System.Configuration.ConfigurationElementCollectionType.BasicMapAlternate) { collectionType.Arguments.Add( new CodeAttributeArgument("AddItemName", new CodeFieldReferenceExpression( GlobalSelfReferenceExpression(element.FullName), xmlPropertyName ) ) ); } else { collectionType.Arguments.Add( new CodeAttributeArgument("AddItemName", new CodePrimitiveExpression(collectionElement.AddItemName) ) ); collectionType.Arguments.Add( new CodeAttributeArgument("RemoveItemName", new CodePrimitiveExpression(collectionElement.RemoveItemName) ) ); collectionType.Arguments.Add( new CodeAttributeArgument("ClearItemsName", new CodePrimitiveExpression(collectionElement.ClearItemsName) ) ); } elementClass.CustomAttributes.Add(collectionType); // Add XmlName field CodeMemberField xmlNameField = new CodeMemberField(_string, xmlPropertyName); elementClass.Members.Add(xmlNameField); xmlNameField.StartDirectives.Add(Region("Constants")); xmlNameField.Comments.Add(DocComment("<summary>")); xmlNameField.Comments.Add(DocComment(string.Format("The XML name of the individual <see cref=\"{0}\"/> instances in this collection.", collectionItemTypeReference))); xmlNameField.Comments.Add(DocComment("</summary>")); xmlNameField.CustomAttributes.Add(_generatedCodeAttribute); xmlNameField.Attributes = MemberAttributes.Const | MemberAttributes.Assembly; xmlNameField.InitExpression = new CodePrimitiveExpression(collectionElement.XmlItemName); xmlNameField.EndDirectives.Add(EndRegion()); // Add collection type property CodeMemberProperty collectionTypeProperty = new CodeMemberProperty(); elementClass.Members.Add(collectionTypeProperty); collectionTypeProperty.StartDirectives.Add(Region("Overrides")); collectionTypeProperty.Comments.Add(DocComment("<summary>")); collectionTypeProperty.Comments.Add(DocComment(string.Format("Gets the type of the <see cref=\"{0}\"/>.", configurationElementCollectionTypeReference))); collectionTypeProperty.Comments.Add(DocComment("</summary>")); collectionTypeProperty.Comments.Add(DocComment(string.Format("<returns>The <see cref=\"{0}\"/> of this collection.</returns>", GetTypeReferenceString(typeof(System.Configuration.ConfigurationElementCollectionType))))); collectionTypeProperty.CustomAttributes.Add(_generatedCodeAttribute); collectionTypeProperty.Attributes = MemberAttributes.Public | MemberAttributes.Override; collectionTypeProperty.Type = GlobalReference(typeof(System.Configuration.ConfigurationElementCollectionType)); collectionTypeProperty.Name = "CollectionType"; collectionTypeProperty.HasGet = true; collectionTypeProperty.GetStatements.Add( new CodeMethodReturnStatement( new CodeFieldReferenceExpression( GlobalReferenceExpression(collectionElement.CollectionType.GetType()), Enum.GetName(collectionElement.CollectionType.GetType(), collectionElement.CollectionType) ) ) ); // Add ElementName property CodeMemberProperty elementNameProperty = new CodeMemberProperty(); elementClass.Members.Add(elementNameProperty); elementNameProperty.Comments.Add(DocComment("<summary>")); elementNameProperty.Comments.Add(DocComment("Gets the name used to identify this collection of elements")); elementNameProperty.Comments.Add(DocComment("</summary>")); elementNameProperty.CustomAttributes.Add(_generatedCodeAttribute); elementNameProperty.Attributes = MemberAttributes.Family | MemberAttributes.Override; elementNameProperty.Type = _string; elementNameProperty.Name = "ElementName"; elementNameProperty.HasGet = true; elementNameProperty.GetStatements.Add( new CodeMethodReturnStatement( new CodeFieldReferenceExpression( GlobalSelfReferenceExpression(element.FullName), xmlPropertyName ) ) ); // Add IsElementName method CodeMemberMethod isElementNameMethod = new CodeMemberMethod(); elementClass.Members.Add(isElementNameMethod); isElementNameMethod.Comments.Add(DocComment("<summary>")); isElementNameMethod.Comments.Add(DocComment(string.Format("Indicates whether the specified <see cref=\"{0}\"/> exists in the <see cref=\"{1}\"/>.", configurationElementTypeReference, configurationElementCollectionTypeReference))); isElementNameMethod.Comments.Add(DocComment("</summary>")); isElementNameMethod.Comments.Add(DocComment("<param name=\"elementName\">The name of the element to verify.</param>")); isElementNameMethod.Comments.Add(DocComment("<returns>")); isElementNameMethod.Comments.Add(DocComment("<see langword=\"true\"/> if the element exists in the collection; otherwise, <see langword=\"false\"/>.")); isElementNameMethod.Comments.Add(DocComment("</returns>")); isElementNameMethod.CustomAttributes.Add(_generatedCodeAttribute); isElementNameMethod.Attributes = MemberAttributes.Family | MemberAttributes.Override; isElementNameMethod.ReturnType = GlobalReference(typeof(bool)); isElementNameMethod.Name = "IsElementName"; isElementNameMethod.Parameters.Add(new CodeParameterDeclarationExpression(_string, "elementName")); isElementNameMethod.Statements.Add( new CodeMethodReturnStatement( new CodeBinaryOperatorExpression( new CodeArgumentReferenceExpression("elementName"), CodeBinaryOperatorType.ValueEquality, new CodeFieldReferenceExpression( GlobalSelfReferenceExpression(string.Format("{0}.{1}", element.ActualNamespace, element.Name)), xmlNameField.Name ) ) ) ); // Add GetElementKey method CodeMemberMethod getElementKeyMethod = new CodeMemberMethod(); elementClass.Members.Add(getElementKeyMethod); getElementKeyMethod.Comments.Add(DocComment("<summary>")); getElementKeyMethod.Comments.Add(DocComment("Gets the element key for the specified configuration element.")); getElementKeyMethod.Comments.Add(DocComment("</summary>")); getElementKeyMethod.Comments.Add(DocComment(string.Format("<param name=\"element\">The <see cref=\"{0}\"/> to return the key for.</param>", configurationElementTypeReference))); getElementKeyMethod.Comments.Add(DocComment("<returns>")); getElementKeyMethod.Comments.Add(DocComment(string.Format("An <see cref=\"{0}\"/> that acts as the key for the specified <see cref=\"{1}\"/>.", GetTypeReferenceString(typeof(object)), configurationElementTypeReference))); getElementKeyMethod.Comments.Add(DocComment("</returns>")); getElementKeyMethod.CustomAttributes.Add(_generatedCodeAttribute); getElementKeyMethod.Attributes = MemberAttributes.Family | MemberAttributes.Override; getElementKeyMethod.ReturnType = _object; getElementKeyMethod.Name = "GetElementKey"; getElementKeyMethod.Parameters.Add(new CodeParameterDeclarationExpression(GlobalReference(typeof(System.Configuration.ConfigurationElement)), "element")); if (keyProperty != null) { getElementKeyMethod.Statements.Add( new CodeMethodReturnStatement( new CodeFieldReferenceExpression( new CodeCastExpression( GlobalSelfReference(collectionElement.ItemType.FullName), new CodeArgumentReferenceExpression("element") ), keyProperty.Name ) ) ); } else { getElementKeyMethod.Statements.Add( new CodeMethodReturnStatement( new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("element"), "GetHashCode" ) ) ); } // Add CreateNewElement method CodeMemberMethod createNewElementMethod = new CodeMemberMethod(); elementClass.Members.Add(createNewElementMethod); createNewElementMethod.Comments.Add(DocComment("<summary>")); createNewElementMethod.Comments.Add(DocComment(string.Format("Creates a new <see cref=\"{0}\"/>.", collectionItemTypeReference))); createNewElementMethod.Comments.Add(DocComment("</summary>")); createNewElementMethod.Comments.Add(DocComment("<returns>")); createNewElementMethod.Comments.Add(DocComment(string.Format("A new <see cref=\"{0}\"/>.", collectionItemTypeReference))); createNewElementMethod.Comments.Add(DocComment("</returns>")); createNewElementMethod.CustomAttributes.Add(_generatedCodeAttribute); createNewElementMethod.Attributes = MemberAttributes.Family | MemberAttributes.Override; createNewElementMethod.ReturnType = GlobalReference(typeof(System.Configuration.ConfigurationElement)); createNewElementMethod.Name = "CreateNewElement"; createNewElementMethod.Statements.Add( new CodeMethodReturnStatement(new CodeObjectCreateExpression(collectionItemType)) ); createNewElementMethod.EndDirectives.Add(EndRegion()); if ((collectionElement.CodeGenOptions & ConfigurationElementCollectionCodeGenOptions.Indexer) == ConfigurationElementCollectionCodeGenOptions.Indexer) { // Add indexer for location CodeMemberProperty locationIndexerProperty = new CodeMemberProperty(); elementClass.Members.Add(locationIndexerProperty); locationIndexerProperty.StartDirectives.Add(Region("Indexer")); locationIndexerProperty.Comments.Add(DocComment("<summary>")); locationIndexerProperty.Comments.Add(DocComment(string.Format("Gets the <see cref=\"{0}\"/> at the specified index.", collectionItemTypeReference))); locationIndexerProperty.Comments.Add(DocComment("</summary>")); locationIndexerProperty.Comments.Add(DocComment(string.Format("<param name=\"index\">The index of the <see cref=\"{0}\"/> to retrieve.</param>", collectionItemTypeReference))); locationIndexerProperty.CustomAttributes.Add(_generatedCodeAttribute); locationIndexerProperty.Attributes = MemberAttributes.Public | MemberAttributes.Final | MemberAttributes.Overloaded; locationIndexerProperty.Type = GlobalSelfReference(collectionElement.ItemType.FullName); locationIndexerProperty.Name = "Item"; locationIndexerProperty.Parameters.Add(new CodeParameterDeclarationExpression(_int, "index")); locationIndexerProperty.HasGet = true; locationIndexerProperty.GetStatements.Add( new CodeMethodReturnStatement( new CodeCastExpression( collectionItemType, new CodeMethodInvokeExpression( _base, "BaseGet", new CodeArgumentReferenceExpression("index") ) ) ) ); // Add GetItemByKey method if (keyProperty != null) { // Add GetItemByKey method for collections have an explicitly set key property CodeMemberProperty keyIndexerProperty = new CodeMemberProperty(); elementClass.Members.Add(keyIndexerProperty); keyIndexerProperty.Comments.Add(DocComment("<summary>")); keyIndexerProperty.Comments.Add(DocComment(string.Format("Gets the <see cref=\"{0}\"/> with the specified key.", collectionItemTypeReference))); keyIndexerProperty.Comments.Add(DocComment("</summary>")); keyIndexerProperty.Comments.Add(DocComment(string.Format("<param name=\"{0}\">The key of the <see cref=\"{1}\"/> to retrieve.</param>", keyProperty.XmlName, collectionItemTypeReference))); keyIndexerProperty.CustomAttributes.Add(_generatedCodeAttribute); keyIndexerProperty.Attributes = MemberAttributes.Public | MemberAttributes.Final | MemberAttributes.Overloaded; keyIndexerProperty.Type = collectionItemType; keyIndexerProperty.Name = "Item"; keyIndexerProperty.Parameters.Add(new CodeParameterDeclarationExpression(_object, keyProperty.XmlName)); keyIndexerProperty.GetStatements.Add( new CodeMethodReturnStatement( new CodeCastExpression( collectionItemType, new CodeMethodInvokeExpression( _base, "BaseGet", new CodeArgumentReferenceExpression(keyProperty.XmlName) ) ) ) ); keyIndexerProperty.EndDirectives.Add(EndRegion()); } else { locationIndexerProperty.EndDirectives.Add(EndRegion()); } } if ((collectionElement.CodeGenOptions & ConfigurationElementCollectionCodeGenOptions.AddMethod) == ConfigurationElementCollectionCodeGenOptions.AddMethod || (collectionElement.CodeGenOptions & ConfigurationElementCollectionCodeGenOptions.ICollection) == ConfigurationElementCollectionCodeGenOptions.ICollection) { // Add Add method CodeMemberMethod addMethod = new CodeMemberMethod(); elementClass.Members.Add(addMethod); addMethod.StartDirectives.Add(Region("Add")); addMethod.Comments.Add(DocComment("<summary>")); addMethod.Comments.Add(DocComment(string.Format("Adds the specified <see cref=\"{0}\"/> to the <see cref=\"{1}\"/>.", collectionItemTypeReference, configurationElementCollectionTypeReference))); addMethod.Comments.Add(DocComment("</summary>")); addMethod.Comments.Add(DocComment(string.Format("<param name=\"{0}\">The <see cref=\"{1}\"/> to add.</param>", collectionElement.XmlItemName, collectionItemTypeReference))); addMethod.CustomAttributes.Add(_generatedCodeAttribute); addMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; addMethod.ReturnType = _void; addMethod.Name = "Add"; addMethod.Parameters.Add(new CodeParameterDeclarationExpression(GlobalSelfReference(collectionElement.ItemType.FullName), collectionElement.XmlItemName)); addMethod.Statements.Add( new CodeMethodInvokeExpression( _base, "BaseAdd", new CodeArgumentReferenceExpression(collectionElement.XmlItemName) ) ); addMethod.EndDirectives.Add(EndRegion()); } if ((collectionElement.CodeGenOptions & ConfigurationElementCollectionCodeGenOptions.RemoveMethod) == ConfigurationElementCollectionCodeGenOptions.RemoveMethod || (collectionElement.CodeGenOptions & ConfigurationElementCollectionCodeGenOptions.ICollection) == ConfigurationElementCollectionCodeGenOptions.ICollection) { // Add Remove method CodeMemberMethod removeMethod = new CodeMemberMethod(); elementClass.Members.Add(removeMethod); removeMethod.StartDirectives.Add(Region("Remove")); removeMethod.Comments.Add(DocComment("<summary>")); removeMethod.Comments.Add(DocComment(string.Format("Removes the specified <see cref=\"{0}\"/> from the <see cref=\"{1}\"/>.", collectionItemTypeReference, configurationElementCollectionTypeReference))); removeMethod.Comments.Add(DocComment("</summary>")); removeMethod.Comments.Add(DocComment(string.Format("<param name=\"{0}\">The <see cref=\"{1}\"/> to remove.</param>", collectionElement.XmlItemName, collectionItemTypeReference))); removeMethod.CustomAttributes.Add(_generatedCodeAttribute); removeMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; removeMethod.ReturnType = _void; removeMethod.Name = "Remove"; removeMethod.Parameters.Add(new CodeParameterDeclarationExpression(collectionItemType, collectionElement.XmlItemName)); removeMethod.Statements.Add( new CodeMethodInvokeExpression( _base, "BaseRemove", new CodeMethodInvokeExpression( _this, "GetElementKey", new CodeArgumentReferenceExpression(collectionElement.XmlItemName) ) ) ); removeMethod.EndDirectives.Add(EndRegion()); } if ((collectionElement.CodeGenOptions & ConfigurationElementCollectionCodeGenOptions.GetItemMethods) == ConfigurationElementCollectionCodeGenOptions.GetItemMethods) { // Add GetItemAt method CodeMemberMethod getItemAtMethod = new CodeMemberMethod(); elementClass.Members.Add(getItemAtMethod); getItemAtMethod.StartDirectives.Add(Region("GetItem")); getItemAtMethod.Comments.Add(DocComment("<summary>")); getItemAtMethod.Comments.Add(DocComment(string.Format("Gets the <see cref=\"{0}\"/> at the specified index.", collectionItemTypeReference))); getItemAtMethod.Comments.Add(DocComment("</summary>")); getItemAtMethod.Comments.Add(DocComment(string.Format("<param name=\"index\">The index of the <see cref=\"{0}\"/> to retrieve.</param>", collectionItemTypeReference))); getItemAtMethod.CustomAttributes.Add(_generatedCodeAttribute); getItemAtMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; getItemAtMethod.ReturnType = collectionItemType; getItemAtMethod.Name = "GetItemAt"; getItemAtMethod.Parameters.Add(new CodeParameterDeclarationExpression(_int, "index")); getItemAtMethod.Statements.Add( new CodeMethodReturnStatement( new CodeCastExpression( collectionItemType, new CodeMethodInvokeExpression( _base, "BaseGet", new CodeArgumentReferenceExpression("index") ) ) ) ); // Add GetItemByKey method if (keyProperty != null) { // Add GetItemByKey method for collections have an explicitly set key property CodeMemberMethod getItemByKeyMethod = new CodeMemberMethod(); elementClass.Members.Add(getItemByKeyMethod); getItemByKeyMethod.Comments.Add(DocComment("<summary>")); getItemByKeyMethod.Comments.Add(DocComment(string.Format("Gets the <see cref=\"{0}\"/> with the specified key.", collectionItemTypeReference))); getItemByKeyMethod.Comments.Add(DocComment("</summary>")); getItemByKeyMethod.Comments.Add(DocComment(string.Format("<param name=\"{0}\">The key of the <see cref=\"{1}\"/> to retrieve.</param>", keyProperty.XmlName, collectionItemTypeReference))); getItemByKeyMethod.CustomAttributes.Add(_generatedCodeAttribute); getItemByKeyMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; getItemByKeyMethod.ReturnType = collectionItemType; getItemByKeyMethod.Name = "GetItemByKey"; getItemByKeyMethod.Parameters.Add(new CodeParameterDeclarationExpression(GlobalReference(keyProperty.TypeName), keyProperty.XmlName)); getItemByKeyMethod.Statements.Add( new CodeMethodReturnStatement( new CodeCastExpression( collectionItemType, new CodeMethodInvokeExpression( _base, "BaseGet", new CodeCastExpression( _object, new CodeArgumentReferenceExpression(keyProperty.XmlName) ) ) ) ) ); getItemByKeyMethod.EndDirectives.Add(EndRegion()); } else { getItemAtMethod.EndDirectives.Add(EndRegion()); } } if ((collectionElement.CodeGenOptions & ConfigurationElementCollectionCodeGenOptions.ICollection) == ConfigurationElementCollectionCodeGenOptions.ICollection) { // Add Clear method CodeMemberMethod clearMethod = new CodeMemberMethod(); elementClass.Members.Add(clearMethod); clearMethod.StartDirectives.Add(Region("ICollection")); clearMethod.Comments.Add(DocComment("<summary>")); clearMethod.Comments.Add(DocComment(string.Format("Removes all items from the <see cref=\"{0}\"/>.", configurationElementCollectionTypeReference))); clearMethod.Comments.Add(DocComment("</summary>")); clearMethod.CustomAttributes.Add(_generatedCodeAttribute); clearMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; clearMethod.ReturnType = _void; clearMethod.Name = "Clear"; clearMethod.Statements.Add( new CodeMethodInvokeExpression(_base, "BaseClear") ); //Add Contains method CodeMemberMethod containsMethod = new CodeMemberMethod(); elementClass.Members.Add(containsMethod); containsMethod.Comments.Add(DocComment("<summary>")); containsMethod.Comments.Add(DocComment(string.Format("Determines whether the <see cref=\"{0}\"/> contains a specific value.", configurationElementCollectionTypeReference))); containsMethod.Comments.Add(DocComment("</summary>")); containsMethod.Comments.Add(DocComment(string.Format("<param name=\"{0}\">The object to locate in the <see cref=\"{1}\"/>.</param>", collectionElement.XmlItemName, collectionItemTypeReference))); containsMethod.CustomAttributes.Add(_generatedCodeAttribute); containsMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; containsMethod.ReturnType = _bool; containsMethod.Name = "Contains"; containsMethod.Parameters.Add(new CodeParameterDeclarationExpression(collectionItemType, collectionElement.XmlItemName)); containsMethod.Statements.Add( new CodeMethodReturnStatement( new CodeBinaryOperatorExpression( new CodeMethodInvokeExpression(_base, "BaseIndexOf", new CodeArgumentReferenceExpression(collectionElement.XmlItemName)), CodeBinaryOperatorType.GreaterThanOrEqual, new CodePrimitiveExpression(0) ) ) ); //Add CopyTo method CodeMemberMethod copytoMethod = new CodeMemberMethod(); elementClass.Members.Add(copytoMethod); copytoMethod.Comments.Add(DocComment("<summary>")); copytoMethod.Comments.Add(DocComment(string.Format("Copies the elements of the <see cref=\"{0}\"/> to an <see cref=\"System.Array\"/>, starting at a particular <see cref=\"System.Array\"/> index.", configurationElementCollectionTypeReference))); copytoMethod.Comments.Add(DocComment("</summary>")); copytoMethod.Comments.Add(DocComment(string.Format("<param name=\"array\">The one-dimensional <see cref=\"System.Array\"/> that is the destination of the elements copied from <see cref=\"{0}\"/>. The <see cref=\"System.Array\"/> must have zero-based indexing.</param>", configurationElementCollectionTypeReference))); copytoMethod.Comments.Add(DocComment("<param name=\"arrayIndex\">The zero-based index in <paramref name=\"array\"/> at which copying begins.</param>")); copytoMethod.CustomAttributes.Add(_generatedCodeAttribute); copytoMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; copytoMethod.ReturnType = _void; copytoMethod.Name = "CopyTo"; copytoMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(collectionItemTypeReference, 1), "array")); copytoMethod.Parameters.Add(new CodeParameterDeclarationExpression(_int, "arrayIndex")); copytoMethod.Statements.Add( new CodeMethodInvokeExpression(_base, "CopyTo", new CodeArgumentReferenceExpression("array"), new CodeArgumentReferenceExpression("arrayIndex")) ); //Add ICollection.IsReadOnly property CodeMemberProperty isReadOnlyProperty = new CodeMemberProperty(); elementClass.Members.Add(isReadOnlyProperty); isReadOnlyProperty.Comments.Add(DocComment("<summary>")); isReadOnlyProperty.Comments.Add(DocComment(string.Format("Gets a value indicating whether the <see cref=\"{0}\"/> is read-only.", configurationElementCollectionTypeReference))); isReadOnlyProperty.Comments.Add(DocComment("</summary>")); isReadOnlyProperty.CustomAttributes.Add(_generatedCodeAttribute); isReadOnlyProperty.Attributes = MemberAttributes.Private; isReadOnlyProperty.PrivateImplementationType = icollectionTypeReference; isReadOnlyProperty.Type = _bool; isReadOnlyProperty.HasGet = true; isReadOnlyProperty.HasSet = false; isReadOnlyProperty.Name = "IsReadOnly"; isReadOnlyProperty.GetStatements.Add( new CodeMethodReturnStatement( new CodeMethodInvokeExpression(_this, "IsReadOnly") ) ); //Add ICollection.Remove method CodeMemberMethod icRemoveMethod = new CodeMemberMethod(); elementClass.Members.Add(icRemoveMethod); icRemoveMethod.Comments.Add(DocComment("<summary>")); icRemoveMethod.Comments.Add(DocComment(string.Format("Removes the first occurrence of a specific object from the <see cref=\"{0}\"/>.", configurationElementCollectionTypeReference))); icRemoveMethod.Comments.Add(DocComment("</summary>")); icRemoveMethod.Comments.Add(DocComment(string.Format("<param name=\"item\">The <see cref=\"{0}\"/> to remove.</param>", collectionItemTypeReference))); icRemoveMethod.CustomAttributes.Add(_generatedCodeAttribute); icRemoveMethod.Attributes = MemberAttributes.Private; icRemoveMethod.PrivateImplementationType = icollectionTypeReference; icRemoveMethod.ReturnType = _bool; icRemoveMethod.Name = "Remove"; icRemoveMethod.Parameters.Add(new CodeParameterDeclarationExpression(collectionItemType, "item")); icRemoveMethod.Statements.Add( new CodeVariableDeclarationStatement(_int, "idx", new CodeMethodInvokeExpression(_base, "BaseIndexOf", new CodeArgumentReferenceExpression("item")) ) ); icRemoveMethod.Statements.Add( new CodeConditionStatement( new CodeBinaryOperatorExpression( new CodeVariableReferenceExpression("idx"), CodeBinaryOperatorType.IdentityEquality, new CodePrimitiveExpression(-1) ), new CodeMethodReturnStatement(new CodePrimitiveExpression(false)) ) ); icRemoveMethod.Statements.Add( new CodeMethodInvokeExpression(_base, "BaseRemoveAt", new CodeVariableReferenceExpression("idx")) ); icRemoveMethod.Statements.Add( new CodeMethodReturnStatement(new CodePrimitiveExpression(true)) ); //Add IEnumerator<> method CodeTypeReference ienumTypeReference = new CodeTypeReference(typeof(System.Collections.Generic.IEnumerator <>), CodeTypeReferenceOptions.GlobalReference); ienumTypeReference.Options = CodeTypeReferenceOptions.GlobalReference | CodeTypeReferenceOptions.GenericTypeParameter; ienumTypeReference.TypeArguments.Add(collectionItemType); CodeTypeReference listTypeReference = new CodeTypeReference(typeof(System.Collections.Generic.List <>), CodeTypeReferenceOptions.GlobalReference); listTypeReference.Options = CodeTypeReferenceOptions.GlobalReference | CodeTypeReferenceOptions.GenericTypeParameter; listTypeReference.TypeArguments.Add(collectionItemType); CodeMemberMethod getEnumeratorMethod = new CodeMemberMethod(); elementClass.Members.Add(getEnumeratorMethod); getEnumeratorMethod.Comments.Add(DocComment("<summary>")); getEnumeratorMethod.Comments.Add(DocComment("Returns an enumerator that iterates through the collection.")); getEnumeratorMethod.Comments.Add(DocComment("</summary>")); getEnumeratorMethod.CustomAttributes.Add(_generatedCodeAttribute); getEnumeratorMethod.Attributes = MemberAttributes.New | MemberAttributes.Public | MemberAttributes.Final; getEnumeratorMethod.ReturnType = ienumTypeReference; getEnumeratorMethod.Name = "GetEnumerator"; getEnumeratorMethod.Statements.Add( new CodeVariableDeclarationStatement(listTypeReference, "list", new CodeObjectCreateExpression(listTypeReference, new CodePropertyReferenceExpression(_base, "Count")) ) ); CodeVariableReferenceExpression varList = new CodeVariableReferenceExpression("list"); getEnumeratorMethod.Statements.Add( new CodeVariableDeclarationStatement(GlobalReference(typeof(System.Collections.IEnumerator)), "iter", new CodeMethodInvokeExpression(_base, "GetEnumerator") ) ); CodeVariableReferenceExpression varIter = new CodeVariableReferenceExpression("iter"); CodeExpressionStatement emptyExpr = new CodeExpressionStatement(new CodeSnippetExpression()); getEnumeratorMethod.Statements.Add( new CodeIterationStatement( emptyExpr, new CodeMethodInvokeExpression(varIter, "MoveNext"), emptyExpr, new CodeExpressionStatement( new CodeMethodInvokeExpression( varList, "Add", new CodeCastExpression(collectionItemType, new CodePropertyReferenceExpression(varIter, "Current")) ) ) ) ); getEnumeratorMethod.Statements.Add( new CodeMethodReturnStatement(new CodeMethodInvokeExpression(varList, "GetEnumerator") ) ); getEnumeratorMethod.EndDirectives.Add(EndRegion()); } }
private void GenerateProperty(ConfigurationElement element, CodeTypeDeclaration elementClass, ConfigurationProperty property) { CodeAttributeDeclarationCollection customAttributes = new CodeAttributeDeclarationCollection(); foreach (Attribute customAttribute in property.Attributes) { CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(GlobalReference(customAttribute.Name)); foreach (AttributeParameter parameter in customAttribute.Parameters) { if (!string.IsNullOrEmpty(parameter.Name)) { attribute.Arguments.Add( new CodeAttributeArgument(parameter.Name, new CodeSnippetExpression(parameter.Value))); } else { attribute.Arguments.Add(new CodeAttributeArgument(new CodeSnippetExpression(parameter.Value))); } } customAttributes.Add(attribute); } string xmlPropertyName = string.Format("{0}PropertyName", property.Name); // Property's XML name field CodeMemberField xmlPropertyNameField = new CodeMemberField(_string, xmlPropertyName); elementClass.Members.Add(xmlPropertyNameField); xmlPropertyNameField.StartDirectives.Add(Region(string.Format("{0} Property", property.Name))); xmlPropertyNameField.Comments.Add(DocComment("<summary>")); xmlPropertyNameField.Comments.Add(DocComment(string.Format("The XML name of the <see cref=\"{0}\"/> property.", property.Name))); xmlPropertyNameField.Comments.Add(DocComment("</summary>")); xmlPropertyNameField.CustomAttributes.Add(_generatedCodeAttribute); xmlPropertyNameField.Attributes = MemberAttributes.Assembly | MemberAttributes.Const; xmlPropertyNameField.InitExpression = new CodePrimitiveExpression(property.XmlName); // Property's property CodeMemberProperty propertyProperty = new CodeMemberProperty(); elementClass.Members.Add(propertyProperty); // Set modifiers, type and name propertyProperty.Attributes = MemberAttributes.Public; // | MemberAttributes.Final; // [a.moore] Removed to allow for TDD. propertyProperty.Type = (property is ElementProperty) ? GlobalSelfReference(property.TypeName) : GlobalReference(property.TypeName); propertyProperty.Name = property.Name; propertyProperty.Comments.Add(DocComment("<summary>")); propertyProperty.Comments.Add(DocComment(EscapeStringChars(property.DocumentationPropertyText))); propertyProperty.Comments.Add(DocComment("</summary>")); propertyProperty.CustomAttributes.Add(_generatedCodeAttribute); propertyProperty.CustomAttributes.AddRange(customAttributes); // Add conditional metadata attributes if (!string.IsNullOrEmpty(property.DocumentationText)) { propertyProperty.CustomAttributes.Add(new CodeAttributeDeclaration(GlobalReference(typeof(System.ComponentModel.DescriptionAttribute)), new CodeAttributeArgument(new CodePrimitiveExpression(EscapeStringChars(property.DocumentationText))))); } if (!property.Browsable) { propertyProperty.CustomAttributes.Add(new CodeAttributeDeclaration(GlobalReference(typeof(System.ComponentModel.BrowsableAttribute)), new CodeAttributeArgument(new CodePrimitiveExpression(false)))); } if (property.IsReadOnly) { propertyProperty.CustomAttributes.Add(new CodeAttributeDeclaration(GlobalReference(typeof(System.ComponentModel.ReadOnlyAttribute)), new CodeAttributeArgument(new CodePrimitiveExpression(true)))); } if (!string.IsNullOrEmpty(property.Category)) { propertyProperty.CustomAttributes.Add(new CodeAttributeDeclaration(GlobalReference(typeof(System.ComponentModel.CategoryAttribute)), new CodeAttributeArgument(new CodePrimitiveExpression(property.Category)))); } if (!string.IsNullOrEmpty(property.DisplayName)) { propertyProperty.CustomAttributes.Add(new CodeAttributeDeclaration(GlobalReference(typeof(System.ComponentModel.DisplayNameAttribute)), new CodeAttributeArgument(new CodePrimitiveExpression(property.DisplayName)))); } if (property is AttributeProperty) { AttributeProperty attributeProperty = (AttributeProperty)property; if (attributeProperty.CustomEditor == CustomEditors.FileNameEditor) { propertyProperty.CustomAttributes.Add( new CodeAttributeDeclaration( GlobalReference(typeof(System.ComponentModel.EditorAttribute)), new CodeAttributeArgument(_typeof("System.Windows.Forms.Design.FileNameEditor")), new CodeAttributeArgument(_typeof("System.Drawing.Design.UITypeEditor")) ) ); } else if (attributeProperty.CustomEditor == CustomEditors.FolderNameEditor) { propertyProperty.CustomAttributes.Add( new CodeAttributeDeclaration( GlobalReference(typeof(System.ComponentModel.EditorAttribute)), new CodeAttributeArgument(_typeof("System.Windows.Forms.Design.FolderNameEditor")), new CodeAttributeArgument(_typeof("System.Drawing.Design.UITypeEditor")) ) ); } } // Add validator if (property.Validator != null) { GenerateValidator(element, elementClass, propertyProperty, property); } // Add converter if (property.TypeConverter != TypeConverters.None) { GenerateConverter(propertyProperty, property); } // Add ConfigurationPropertyAttribute CodeAttributeDeclaration configPropertyAttribute = new CodeAttributeDeclaration(GlobalReference(typeof(System.Configuration.ConfigurationPropertyAttribute)), new CodeAttributeArgument(new CodeFieldReferenceExpression(GlobalSelfReferenceExpression(string.Format("{0}.{1}", element.ActualNamespace, element.Name)), xmlPropertyNameField.Name)), new CodeAttributeArgument("IsRequired", new CodePrimitiveExpression(property.IsRequired)), new CodeAttributeArgument("IsKey", new CodePrimitiveExpression(property.IsKey)), new CodeAttributeArgument("IsDefaultCollection", new CodePrimitiveExpression(property.IsDefaultCollection))); if (property is AttributeProperty) { AttributeProperty attributeProperty = (AttributeProperty)property; if (!string.IsNullOrEmpty(attributeProperty.DefaultValue)) { configPropertyAttribute.Arguments.Add(new CodeAttributeArgument("DefaultValue", new CodeSnippetExpression(attributeProperty.DefaultValue))); } } propertyProperty.CustomAttributes.Add(configPropertyAttribute); CodeTypeReference castType; if (property is ElementProperty) { castType = GlobalSelfReference(property.TypeName); } else { castType = GlobalReference(property.TypeName); } // Get method propertyProperty.HasGet = true; propertyProperty.GetStatements.Add( new CodeMethodReturnStatement( new CodeCastExpression( castType, new CodeIndexerExpression( _base, new CodeFieldReferenceExpression( GlobalSelfReferenceExpression(string.Format("{0}.{1}", element.ActualNamespace, element.Name)), xmlPropertyName ) ) ) ) ); if (!property.IsReadOnly) { // Set method propertyProperty.HasSet = true; propertyProperty.SetStatements.Add( new CodeAssignStatement( new CodeIndexerExpression( _base, new CodeFieldReferenceExpression( GlobalSelfReferenceExpression(string.Format("{0}.{1}", element.ActualNamespace, element.Name)), xmlPropertyName ) ), new CodePropertySetValueReferenceExpression() ) ); } propertyProperty.EndDirectives.Add(EndRegion()); }