// -------------------------------------------------------------------------------------------------------------------- // // N/A // // // Implements code generation extension for .Net Framework 3.0 // // // Updated 2010-01-20 Deerwood McCord Jr. Cleaned CodeSnippetStatements by replacing with specific CodeDom Expressions // // -------------------------------------------------------------------------------------------------------------------- namespace Xsd2Code.Library.Extensions { using System.CodeDom; using System.CodeDom.Compiler; using System.Collections.Generic; using System.IO; using System.Xml.Schema; using Helpers; /// /// Implements code generation extension for .Net Framework 3.0 /// [CodeExtension(TargetFramework.Net30)] public class Net30Extension : CodeExtension { #region Private Fields /// /// List the properties that will change to auto properties /// private readonly List autoPropertyListField = new List(); /// /// List the fields to be deleted /// private readonly List fieldListToRemoveField = new List(); /// /// List fields that require an initialization in the constructor /// private readonly List fieldWithAssignementInCtorListField = new List(); #endregion #region Protected methods /// /// Processes the class. /// /// The code namespace. /// The input xsd schema. /// Represents a type declaration for a class, structure, interface, or enumeration protected override void ProcessClass(CodeNamespace codeNamespace, XmlSchema schema, CodeTypeDeclaration type) { this.autoPropertyListField.Clear(); this.fieldListToRemoveField.Clear(); this.fieldWithAssignementInCtorListField.Clear(); // looks for properties that can not become automatic property CodeConstructor ctor = null; foreach (CodeTypeMember member in type.Members) { if (member is CodeConstructor) ctor = member as CodeConstructor; } if (ctor != null) { foreach (var statement in ctor.Statements) { var codeAssignStatement = statement as CodeAssignStatement; if (codeAssignStatement == null) continue; var code = codeAssignStatement.Left as CodeFieldReferenceExpression; if (code != null) { this.fieldWithAssignementInCtorListField.Add(code.FieldName); } } } base.ProcessClass(codeNamespace, schema, type); // generate automatic properties this.GenerateAutomaticProperties(type); } /// /// Create data contract attribute /// /// Code type declaration /// XML schema protected override void CreateDataContractAttribute(CodeTypeDeclaration type, XmlSchema schema) { base.CreateDataContractAttribute(type, schema); if (GeneratorContext.GeneratorParams.GenerateDataContracts) { var attributeType = new CodeTypeReference("System.Runtime.Serialization.DataContractAttribute"); var codeAttributeArgument = new List(); //var typeName = string.Concat('"', type.Name, '"'); //codeAttributeArgument.Add(new CodeAttributeArgument("Name", new CodeSnippetExpression(typeName))); codeAttributeArgument.Add(new CodeAttributeArgument("Name", new CodePrimitiveExpression(type.Name))); if (!string.IsNullOrEmpty(schema.TargetNamespace)) { //var targetNamespace = string.Concat('\"', schema.TargetNamespace, '\"'); //codeAttributeArgument.Add(new CodeAttributeArgument("Namespace", new CodeSnippetExpression(targetNamespace))); codeAttributeArgument.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(schema.TargetNamespace))); } type.CustomAttributes.Add(new CodeAttributeDeclaration(attributeType, codeAttributeArgument.ToArray())); } } /// /// Creates the data member attribute. /// /// Represents a declaration for a property of a type. protected override void CreateDataMemberAttribute(CodeMemberProperty prop) { base.CreateDataMemberAttribute(prop); if (GeneratorContext.GeneratorParams.GenerateDataContracts) { var attrib = new CodeTypeReference("System.Runtime.Serialization.DataMemberAttribute"); prop.CustomAttributes.Add(new CodeAttributeDeclaration(attrib)); } } /// /// Import namespaces /// /// Code namespace protected override void ImportNamespaces(CodeNamespace code) { base.ImportNamespaces(code); if (GeneratorContext.GeneratorParams.GenerateDataContracts) code.Imports.Add(new CodeNamespaceImport("System.Runtime.Serialization")); } /// /// Property process /// /// Represents a type declaration for a class, structure, interface, or enumeration /// The ns. /// Type members include fields, methods, properties, constructors and nested types /// Represent the root element in schema /// XML Schema protected override void ProcessProperty(CodeTypeDeclaration type, CodeNamespace ns, CodeTypeMember member, XmlSchemaElement xmlElement, XmlSchema schema) { // Get now if property is array before base.ProcessProperty call. var prop = (CodeMemberProperty)member; base.ProcessProperty(type, ns, member, xmlElement, schema); // Generate automatic properties. if (GeneratorContext.GeneratorParams.Language == GenerationLanguage.CSharp) { if (GeneratorContext.GeneratorParams.AutomaticProperties) { if (!this.IsComplexType(prop.Type, ns)) { // Exclude collection type if (collectionTypesFields.IndexOf(prop.Name) == -1) { // Get private fieldName var propReturnStatment = prop.GetStatements[0] as CodeMethodReturnStatement; if (propReturnStatment != null) { var field = propReturnStatment.Expression as CodeFieldReferenceExpression; if (field != null) { // Check if private field don't need initialisation in ctor (defaut value). if (this.fieldWithAssignementInCtorListField.FindIndex(p => p == field.FieldName) == -1) { this.autoPropertyListField.Add(member as CodeMemberProperty); } } } } } } } } /// /// process Fields. /// /// CodeTypeMember member /// CodeMemberMethod constructor /// CodeNamespace XSD /// Indicates if create a new constructor protected override void ProcessFields(CodeTypeMember member, CodeMemberMethod ctor, CodeNamespace ns, ref bool addedToConstructor) { // Get now if filed is array before base.ProcessProperty call. var field = (CodeMemberField)member; bool isArray = field.Type.ArrayElementType != null; base.ProcessFields(member, ctor, ns, ref addedToConstructor); // Generate automatic properties. if (GeneratorContext.GeneratorParams.Language == GenerationLanguage.CSharp) { if (GeneratorContext.GeneratorParams.AutomaticProperties) { if (!isArray) { if (!this.IsComplexType(field.Type, ns)) { // If this field is not assigned in ctor, add it in remove list. // with automatic property, don't need to keep private field. if (this.fieldWithAssignementInCtorListField.FindIndex(p => p == field.Name) == -1) { this.fieldListToRemoveField.Add(field); } } } } } } #endregion #region static methods /// /// Outputs the attribute argument. /// /// Represents an argument used in a metadata attribute declaration. /// transform attribute into srting private static string AttributeArgumentToString(CodeAttributeArgument arg) { var strWriter = new StringWriter(); var provider = CodeDomProviderFactory.GetProvider(GeneratorContext.GeneratorParams.Language); if (!string.IsNullOrEmpty(arg.Name)) { strWriter.Write(arg.Name); strWriter.Write("="); } provider.GenerateCodeFromExpression(arg.Value, strWriter, new CodeGeneratorOptions()); var strrdr = new StringReader(strWriter.ToString()); return strrdr.ReadToEnd(); } #endregion /// /// Outputs the attribute argument. /// /// Represents an argument used in a metadata attribute declaration. /// transform attribute into srting private static string ExpressionToString(CodeExpression arg) { var strWriter = new StringWriter(); var provider = CodeDomProviderFactory.GetProvider(GeneratorContext.GeneratorParams.Language); provider.GenerateCodeFromExpression(arg, strWriter, new CodeGeneratorOptions()); var strrdr = new StringReader(strWriter.ToString()); return strrdr.ReadToEnd(); } #region Private methods /// /// Generates the automatic properties. /// /// Represents a type declaration for a class, structure, interface, or enumeration. private void GenerateAutomaticProperties(CodeTypeDeclaration type) { if (Equals(GeneratorContext.GeneratorParams.Language, GenerationLanguage.CSharp)) { // If databinding is disable, use automatic property if (GeneratorContext.GeneratorParams.AutomaticProperties) { foreach (var item in this.autoPropertyListField) { var cm = new CodeSnippetTypeMember(); bool transformToAutomaticproperty = true; var attributesString = new List(); foreach (var attribute in item.CustomAttributes) { var attrib = attribute as CodeAttributeDeclaration; if (attrib != null) { // Don't transform property with default value. if (attrib.Name == "System.ComponentModel.DefaultValueAttribute") { transformToAutomaticproperty = false; } else { string attributesArgument = string.Empty; foreach (var arg in attrib.Arguments) { var argument = arg as CodeAttributeArgument; if (argument != null) { attributesArgument += AttributeArgumentToString(argument); } } attributesString.Add(string.Format("[{0}({1})]", attrib.Name, attributesArgument)); } } } if (transformToAutomaticproperty) { foreach (var attribute in attributesString) { cm.Text += " " + attribute + "\n"; } var ct = new CodeTypeReferenceExpression(item.Type); var prop = ExpressionToString(ct); var text = string.Format(" public {0} {1} ", prop, item.Name); cm.Text += string.Concat(text, "{get; set;}\n"); cm.Comments.AddRange(item.Comments); type.Members.Add(cm); type.Members.Remove(item); } } // Now remove all private fileds foreach (var item in this.fieldListToRemoveField) { type.Members.Remove(item); } } } } #endregion } }