// -------------------------------------------------------------------------------------------------------------------- // // N/A // // // Base class for code generation extension // // // Revision history: // Created 2009-03-16 by Ruslan Urban // based on GeneratorExtension.cs // Updated 2009-05-18 move wcf CodeDom generation into Net35Extention.cs by Pascal Cabanel // Updated 2009-05-18 Remove .Net 2.0 XML attributes by Pascal Cabanel // Updated 2009-06-16 Add EntityBase class. // Add new serialize/deserialize methods. // Dispose object in serialize/deserialize methods. // Updated 2010-01-07 Deerwood McCord Jr. (DCM) applied patch from Rob van der Veer // Updated 2010-01-20 Deerwood McCord Jr. Cleaned CodeSnippetStatements by replacing with specific CodeDom Expressions // Refactored OnPropertyChanged to use more CodeDom Specific version found in CodeDomHelper.CreateOnPropertyChangeMethod() // // -------------------------------------------------------------------------------------------------------------------- namespace Xsd2Code.Library.Extensions { using System; using System.CodeDom; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Reflection; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; using Helpers; /// /// Base class for code generation extension /// public abstract class CodeExtension : ICodeExtension { #region private fields /// /// Sorted list for custom collection /// private static readonly SortedList CollectionTypes = new SortedList(); /// /// Contains all enum. /// private static List enumListField; /// /// Contains all collection fields. /// private static List lasyLoadingFields = new List(); /// /// Contains all collection fields. /// protected static List collectionTypesFields = new List(); #endregion #region public method /// /// Process method for cs or vb CodeDom generation /// /// CodeNamespace generated /// XmlSchema to generate public virtual void Process(CodeNamespace code, XmlSchema schema) { this.ImportNamespaces(code); CollectionTypes.Clear(); lasyLoadingFields.Clear(); collectionTypesFields.Clear(); var types = new CodeTypeDeclaration[code.Types.Count]; code.Types.CopyTo(types, 0); // Generate generic base class if (GeneratorContext.GeneratorParams.UseGenericBaseClass) { code.Types.Insert(0, this.GenerateBaseClass()); } enumListField = (from p in types where p.IsEnum select p.Name).ToList(); foreach (var type in types) { //Fixes http://xsd2code.codeplex.com/WorkItem/View.aspx?WorkItemId=8781 // and http://xsd2code.codeplex.com/WorkItem/View.aspx?WorkItemId=6944 if (GeneratorContext.GeneratorParams.ExcludeIncludedTypes) { //if the typeName is NOT defined in the current schema, skip it. if (!ContainsTypeName(schema, type)) { code.Types.Remove(type); continue; } } // Remove default remarks attribute type.Comments.Clear(); // Remove default .Net 2.0 XML attributes if disabled. if (!GeneratorContext.GeneratorParams.GenerateXMLAttributes) { this.RemoveDefaultXmlAttributes(type.CustomAttributes); } if (!type.IsClass && !type.IsStruct) continue; this.ProcessClass(code, schema, type); } foreach (string collName in CollectionTypes.Keys) this.CreateCollectionClass(code, collName); } /// /// Determines whether the specified schema contains the type. /// /// The schema. /// The type. /// /// true if the specified schema contains the type; otherwise, false. /// /// Used to Exclude Included Types from Schema private bool ContainsTypeName(XmlSchema schema, CodeTypeDeclaration type) { foreach (var item in schema.Items) { var complexItem = item as XmlSchemaComplexType; if(complexItem != null) { if (complexItem.Name == type.Name) { return true; } } var elementItem = item as XmlSchemaElement; if (elementItem != null) { if (elementItem.Name == type.Name) { return true; } } } //TODO: Does not work for combined anonymous types //fallback: Check if the namespace attribute of the type equals the namespace of the file. //first, find the XmlType attribute. foreach(CodeAttributeDeclaration attribute in type.CustomAttributes) { if(attribute.Name == "System.Xml.Serialization.XmlTypeAttribute") { foreach(CodeAttributeArgument argument in attribute.Arguments) { if(argument.Name == "Namespace") { if(((CodePrimitiveExpression)argument.Value).Value == schema.TargetNamespace) { return true; } } } } } return false; } #endregion #region protedted methods /// /// Generate defenition of the Clone() method /// /// Represents a type declaration for a class, structure, interface, or enumeration /// return CodeDom clone method protected static CodeTypeMember GetCloneMethod(CodeTypeDeclaration type) { string typeName = GeneratorContext.GeneratorParams.UseGenericBaseClass ? "T" : type.Name; // ---------------------------------------------------------------------- // /// // /// Create clone of this TClass object // /// // public TClass Clone() // { // return ((TClass)this.MemberwiseClone()); // } // ---------------------------------------------------------------------- var cloneMethod = new CodeMemberMethod { Attributes = MemberAttributes.Public, Name = "Clone", ReturnType = new CodeTypeReference(typeName) }; CodeDomHelper.CreateSummaryComment( cloneMethod.Comments, string.Format("Create a clone of this {0} object", typeName)); var memberwiseCloneMethod = new CodeMethodInvokeExpression( new CodeThisReferenceExpression(), "MemberwiseClone"); var statement = new CodeMethodReturnStatement(new CodeCastExpression(typeName, memberwiseCloneMethod)); cloneMethod.Statements.Add(statement); return cloneMethod; } /// /// Processes the class. /// /// The code namespace. /// The input xsd schema. /// Represents a type declaration for a class, structure, interface, or enumeration protected virtual void ProcessClass(CodeNamespace codeNamespace, XmlSchema schema, CodeTypeDeclaration type) { var addedToConstructor = false; var newCTor = false; var ctor = this.GetConstructor(type, ref newCTor); // Inherits from EntityBase if (GeneratorContext.GeneratorParams.UseGenericBaseClass) { var ctr = new CodeTypeReference(GeneratorContext.GeneratorParams.BaseClassName); ctr.TypeArguments.Add(new CodeTypeReference(type.Name)); type.BaseTypes.Add(ctr); } else { if (GeneratorContext.GeneratorParams.EnableDataBinding) type.BaseTypes.Add(typeof(INotifyPropertyChanged)); } // Generate WCF DataContract this.CreateDataContractAttribute(type, schema); XmlSchemaElement currentElement = null; if (GeneratorContext.GeneratorParams.EnableSummaryComment) currentElement = this.CreateSummaryCommentFromSchema(type, schema, currentElement); foreach (CodeTypeMember member in type.Members) { // Remove default remarks attribute member.Comments.Clear(); // Remove default .Net 2.0 XML attributes if disabled. if (!GeneratorContext.GeneratorParams.GenerateXMLAttributes) { this.RemoveDefaultXmlAttributes(member.CustomAttributes); } var codeMember = member as CodeMemberField; if (codeMember != null) this.ProcessFields(codeMember, ctor, codeNamespace, ref addedToConstructor); var codeMemberProperty = member as CodeMemberProperty; if (codeMemberProperty != null) this.ProcessProperty(type, codeNamespace, codeMemberProperty, currentElement, schema); } //DCM: Moved From GeneraterFacade File based removal to CodeDom Style Attribute-based removal if (GeneratorContext.GeneratorParams.DisableDebug) { this.RemoveDebugAttributes(type.CustomAttributes); } // Add new ctor if required if (addedToConstructor && newCTor) type.Members.Add(ctor); // If don't use base class, generate all methods inside class if (!GeneratorContext.GeneratorParams.UseGenericBaseClass) { if (GeneratorContext.GeneratorParams.EnableDataBinding) this.CreateDataBinding(type); if (GeneratorContext.GeneratorParams.IncludeSerializeMethod) { CreateStaticSerializer(type); this.CreateSerializeMethods(type); } if (GeneratorContext.GeneratorParams.GenerateCloneMethod) this.CreateCloneMethod(type); } } /// /// Create data binding /// /// Code type declaration protected virtual void CreateDataBinding(CodeTypeDeclaration type) { // ------------------------------------------------------------------------------- // public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; // ------------------------------------------------------------------------------- var propertyChangedEvent = new CodeMemberEvent { Attributes = MemberAttributes.Final | MemberAttributes.Public, Name = "PropertyChanged", Type = new CodeTypeReference(typeof(PropertyChangedEventHandler)) }; propertyChangedEvent.ImplementationTypes.Add(new CodeTypeReference("INotifyPropertyChanged")); type.Members.Add(propertyChangedEvent); // ----------------------------------------------------------- // protected virtual void OnPropertyChanged(string info) { // PropertyChangedEventHandler handler = PropertyChanged; // if (handler != null) { // handler(this, new PropertyChangedEventArgs(info)); // } // } // ----------------------------------------------------------- /* DCM REMOVED Uses CodeSnippetExpressions var propertyChangedMethod = CreatePropertyChangedMethod(); */ var propertyChangedMethod = CodeDomHelper.CreatePropertyChangedMethod(); type.Members.Add(propertyChangedMethod); } /// /// Creates the property changed method. /// /// CodeMemberMethod on Property Change handler /// /// DCM: Plan on deleting after Beta Period. /// Use Switch and Language specific CodeSnippetExpressions produce method /// VB version /// /// public sub OnPropertyChanged(byval info as string) /// RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info)) /// end sub /// /// /// C# & CPP Version /// /// protected virtual void OnPropertyChanged(string info) { /// PropertyChangedEventHandler handler = PropertyChanged; /// if (handler != null) { /// handler(this, new PropertyChangedEventArgs(info)); /// } /// } /// /// private static CodeMemberMethod CreatePropertyChangedMethod() { var propertyChangedMethod = new CodeMemberMethod { Name = "OnPropertyChanged", Attributes = MemberAttributes.Public }; propertyChangedMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "info")); switch (GeneratorContext.GeneratorParams.Language) { case GenerationLanguage.VisualBasic: propertyChangedMethod.Statements.Add( new CodeExpressionStatement( new CodeSnippetExpression( "RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))"))); break; case GenerationLanguage.CSharp: case GenerationLanguage.VisualCpp: propertyChangedMethod.Statements.Add( new CodeExpressionStatement( new CodeSnippetExpression("PropertyChangedEventHandler handler = PropertyChanged"))); var codeExpressionStatement = new CodeExpressionStatement( new CodeSnippetExpression("handler(this, new PropertyChangedEventArgs(info))")); CodeStatement[] statements = new[] { codeExpressionStatement }; propertyChangedMethod.Statements.Add( new CodeConditionStatement(new CodeSnippetExpression("handler != null"), statements)); break; } return propertyChangedMethod; } /// /// Creates the summary comment from schema. /// /// The code type declaration. /// The input XML schema. /// The current element. /// returns the element found otherwise null protected virtual XmlSchemaElement CreateSummaryCommentFromSchema(CodeTypeDeclaration codeTypeDeclaration, XmlSchema schema, XmlSchemaElement currentElement) { var xmlSchemaElement = this.SearchElementInSchema(codeTypeDeclaration, schema, new List()); if (xmlSchemaElement != null) { currentElement = xmlSchemaElement; if (xmlSchemaElement.Annotation != null) { foreach (var item in xmlSchemaElement.Annotation.Items) { var xmlDoc = item as XmlSchemaDocumentation; if (xmlDoc == null) continue; this.CreateCommentStatment(codeTypeDeclaration.Comments, xmlDoc); } } } return currentElement; } /// /// Creates the collection class. /// /// The code namespace. /// Name of the coll. protected virtual void CreateCollectionClass(CodeNamespace codeNamespace, string collName) { var ctd = new CodeTypeDeclaration(collName) { IsClass = true }; /* DCM REMOVED NOT LANGUAGE INDEPENDENT ctd.BaseTypes.Add(string.Format( "{0}<{1}>", GeneratorContext.GeneratorParams.CollectionBase, CollectionTypes[collName])); DCM REMOVED */ //DCM Changed to Languaged independent CodeDOM ctd.BaseTypes.Add(new CodeTypeReference(GeneratorContext.GeneratorParams.CollectionBase, new[] { new CodeTypeReference(CollectionTypes[collName]) })); ctd.IsPartial = true; bool newCTor = false; var ctor = this.GetConstructor(ctd, ref newCTor); ctd.Members.Add(ctor); codeNamespace.Types.Add(ctd); } /// /// Creates the clone method. /// /// Represents a type declaration for a class, structure, interface, or enumeration. protected virtual void CreateCloneMethod(CodeTypeDeclaration codeTypeDeclaration) { var cloneMethod = GetCloneMethod(codeTypeDeclaration); cloneMethod.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Clone method")); cloneMethod.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, "Clone method")); codeTypeDeclaration.Members.Add(cloneMethod); } /// /// Creates the serialize methods. /// /// Represents a type declaration for a class, structure, interface, or enumeration. protected virtual void CreateSerializeMethods(CodeTypeDeclaration type) { // Serialize var ser = this.CreateSerializeMethod(type); ser.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Serialize/Deserialize")); type.Members.Add(ser); // Deserialize type.Members.AddRange(this.GetOverrideDeserializeMethods(type)); type.Members.Add(this.GetDeserializeMethod(type)); // SaveToFile type.Members.AddRange(this.GetOverrideSaveToFileMethods(type)); type.Members.Add(this.GetSaveToFileMethod()); // LoadFromFile type.Members.AddRange(this.GetOverrideLoadFromFileMethods(type)); var lff = this.GetLoadFromFileMethod(type); lff.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, "Serialize/Deserialize")); type.Members.Add(lff); } /// /// Gets the serialize CodeDOM method. /// /// The type object to serilize. /// return the CodeDOM serialize method protected virtual CodeMemberMethod CreateSerializeMethod(CodeTypeDeclaration type) { var serializeMethod = new CodeMemberMethod { Attributes = MemberAttributes.Public, Name = GeneratorContext.GeneratorParams.SerializeMethodName }; var tryStatmanentsCol = new CodeStatementCollection(); var finallyStatmanentsCol = new CodeStatementCollection(); // ------------------------------------------------------------ // System.IO.StreamReader streamReader = null; // System.IO.MemoryStream memoryStream = null; // ------------------------------------------------------------ serializeMethod.Statements.Add( new CodeVariableDeclarationStatement( new CodeTypeReference(typeof(StreamReader)), "streamReader", new CodePrimitiveExpression(null))); serializeMethod.Statements.Add( new CodeVariableDeclarationStatement( new CodeTypeReference(typeof(MemoryStream)), "memoryStream", new CodePrimitiveExpression(null))); tryStatmanentsCol.Add(new CodeAssignStatement( new CodeVariableReferenceExpression("memoryStream"), CodeDomHelper.CreateInstance(typeof(MemoryStream)))); // -------------------------------------------------------------------------- // Serializer.Serialize(memoryStream, this); // -------------------------------------------------------------------------- tryStatmanentsCol.Add( CodeDomHelper.GetInvokeMethod( "Serializer", "Serialize", new CodeExpression[] { new CodeTypeReferenceExpression("memoryStream"), new CodeThisReferenceExpression() })); // --------------------------------------------------------------------------- // memoryStream.Seek(0, SeekOrigin.Begin); // System.IO.StreamReader streamReader = new System.IO.StreamReader(memoryStream); // --------------------------------------------------------------------------- tryStatmanentsCol.Add( CodeDomHelper.GetInvokeMethod( "memoryStream", "Seek", new CodeExpression[] { new CodePrimitiveExpression(0), new CodeTypeReferenceExpression("System.IO.SeekOrigin.Begin") })); tryStatmanentsCol.Add(new CodeAssignStatement( new CodeVariableReferenceExpression("streamReader"), CodeDomHelper.CreateInstance(typeof(StreamReader), new[] { "memoryStream" }))); var readToEnd = CodeDomHelper.GetInvokeMethod("streamReader", "ReadToEnd"); tryStatmanentsCol.Add(new CodeMethodReturnStatement(readToEnd)); finallyStatmanentsCol.Add(CodeDomHelper.GetDispose("streamReader")); finallyStatmanentsCol.Add(CodeDomHelper.GetDispose("memoryStream")); var tryfinallyStmt = new CodeTryCatchFinallyStatement(tryStatmanentsCol.ToArray(), new CodeCatchClause[0], finallyStatmanentsCol.ToArray()); serializeMethod.Statements.Add(tryfinallyStmt); serializeMethod.ReturnType = new CodeTypeReference(typeof(string)); // -------- // Comments // -------- serializeMethod.Comments.AddRange( CodeDomHelper.GetSummaryComment(string.Format("Serializes current {0} object into an XML document", type.Name))); serializeMethod.Comments.Add(CodeDomHelper.GetReturnComment("string XML value")); return serializeMethod; } /// /// Get Deserialize method /// /// represent a type declaration of class /// Deserialize CodeMemberMethod protected virtual CodeMemberMethod GetDeserializeMethod(CodeTypeDeclaration type) { string deserializeTypeName = GeneratorContext.GeneratorParams.UseGenericBaseClass ? "T" : type.Name; // --------------------------------------- // public static T Deserialize(string xml) // --------------------------------------- var deserializeMethod = new CodeMemberMethod { Attributes = MemberAttributes.Public | MemberAttributes.Static, Name = GeneratorContext.GeneratorParams.DeserializeMethodName }; deserializeMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "xml")); deserializeMethod.ReturnType = new CodeTypeReference(deserializeTypeName); deserializeMethod.Statements.Add( new CodeVariableDeclarationStatement( new CodeTypeReference(typeof(StringReader)), "stringReader", new CodePrimitiveExpression(null))); var tryStatmanentsCol = new CodeStatementCollection(); var finallyStatmanentsCol = new CodeStatementCollection(); // ------------------------------------------------------ // stringReader = new StringReader(xml); // ------------------------------------------------------ var deserializeStatmanents = new CodeStatementCollection(); tryStatmanentsCol.Add(new CodeAssignStatement( new CodeVariableReferenceExpression("stringReader"), new CodeObjectCreateExpression( new CodeTypeReference(typeof(StringReader)), new CodeExpression[] { new CodeArgumentReferenceExpression("xml") }))); // ---------------------------------------------------------- // obj = (ClassName)serializer.Deserialize(xmlReader); // return true; // ---------------------------------------------------------- var deserialize = CodeDomHelper.GetInvokeMethod( "Serializer", "Deserialize", new CodeExpression[] { CodeDomHelper.GetInvokeMethod( "System.Xml.XmlReader", "Create", new CodeExpression[] { new CodeVariableReferenceExpression("stringReader") }) }); var castExpr = new CodeCastExpression(deserializeTypeName, deserialize); var returnStmt = new CodeMethodReturnStatement(castExpr); tryStatmanentsCol.Add(returnStmt); tryStatmanentsCol.AddRange(deserializeStatmanents); finallyStatmanentsCol.Add(CodeDomHelper.GetDispose("stringReader")); var tryfinallyStmt = new CodeTryCatchFinallyStatement(tryStatmanentsCol.ToArray(), new CodeCatchClause[0], finallyStatmanentsCol.ToArray()); deserializeMethod.Statements.Add(tryfinallyStmt); return deserializeMethod; } /// /// Get Deserialize method /// /// represent a type declaration of class /// Deserialize CodeMemberMethod protected virtual CodeMemberMethod[] GetOverrideDeserializeMethods(CodeTypeDeclaration type) { var deserializeMethodList = new List(); string deserializeTypeName = GeneratorContext.GeneratorParams.UseGenericBaseClass ? "T" : type.Name; // ------------------------------------------------------------------------------------- // public static bool Deserialize(string xml, out T obj, out System.Exception exception) // ------------------------------------------------------------------------------------- var deserializeMethod = new CodeMemberMethod { Attributes = MemberAttributes.Public | MemberAttributes.Static, Name = GeneratorContext.GeneratorParams.DeserializeMethodName }; deserializeMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "xml")); var param = new CodeParameterDeclarationExpression(deserializeTypeName, "obj") { Direction = FieldDirection.Out }; deserializeMethod.Parameters.Add(param); param = new CodeParameterDeclarationExpression(typeof(Exception), "exception") { Direction = FieldDirection.Out }; deserializeMethod.Parameters.Add(param); deserializeMethod.ReturnType = new CodeTypeReference(typeof(bool)); // ----------------- // exception = null; // ----------------- deserializeMethod.Statements.Add( new CodeAssignStatement( new CodeArgumentReferenceExpression("exception"), new CodePrimitiveExpression(null))); // ----------------- // obj = default(T); // ----------------- deserializeMethod.Statements.Add( new CodeAssignStatement( new CodeArgumentReferenceExpression("obj"), new CodeDefaultValueExpression(new CodeTypeReference(deserializeTypeName)) )); /* DCM REMOVE Switch Statement Dependent Code switch (GeneratorContext.GeneratorParams.Language) { case GenerationLanguage.CSharp: { deserializeMethod.Statements.Add( new CodeAssignStatement( new CodeArgumentReferenceExpression("obj"), new CodeSnippetExpression(string.Format("default({0})", deserializeTypeName)))); } break; case GenerationLanguage.VisualBasic: { deserializeMethod.Statements.Add( new CodeAssignStatement( new CodeArgumentReferenceExpression("obj"), new CodePrimitiveExpression(null))); } break; } */ // --------------------- // try {...} catch {...} // --------------------- var tryStatmanentsCol = new CodeStatementCollection(); // Call Desrialize method var deserializeInvoke = new CodeMethodInvokeExpression( new CodeMethodReferenceExpression(null, GeneratorContext.GeneratorParams.DeserializeMethodName), new CodeExpression[] { new CodeArgumentReferenceExpression("xml") }); tryStatmanentsCol.Add( new CodeAssignStatement( new CodeArgumentReferenceExpression("obj"), deserializeInvoke)); tryStatmanentsCol.Add(CodeDomHelper.GetReturnTrue()); // catch var catchClauses = CodeDomHelper.GetCatchClause(); var trycatch = new CodeTryCatchFinallyStatement(tryStatmanentsCol.ToArray(), catchClauses); deserializeMethod.Statements.Add(trycatch); // -------- // Comments // -------- deserializeMethod.Comments.AddRange( CodeDomHelper.GetSummaryComment(string.Format("Deserializes workflow markup into an {0} object", type.Name))); deserializeMethod.Comments.Add(CodeDomHelper.GetParamComment("xml", "string workflow markup to deserialize")); deserializeMethod.Comments.Add(CodeDomHelper.GetParamComment("obj", string.Format("Output {0} object", type.Name))); deserializeMethod.Comments.Add(CodeDomHelper.GetParamComment("exception", "output Exception value if deserialize failed")); deserializeMethod.Comments.Add( CodeDomHelper.GetReturnComment("true if this XmlSerializer can deserialize the object; otherwise, false")); deserializeMethodList.Add(deserializeMethod); // ----------------------------------------------------- // public static bool Deserialize(string xml, out T obj) // ----------------------------------------------------- deserializeMethod = new CodeMemberMethod { Attributes = MemberAttributes.Public | MemberAttributes.Static, Name = GeneratorContext.GeneratorParams.DeserializeMethodName }; deserializeMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "xml")); deserializeMethod.ReturnType = new CodeTypeReference(typeof(bool)); param = new CodeParameterDeclarationExpression(deserializeTypeName, "obj") { Direction = FieldDirection.Out }; deserializeMethod.Parameters.Add(param); // --------------------------- // Exception exception = null; // --------------------------- deserializeMethod.Statements.Add( new CodeVariableDeclarationStatement(typeof(Exception), "exception", new CodePrimitiveExpression(null))); // ------------------------------------------------ // return Deserialize(xml, out obj, out exception); // ------------------------------------------------ var xmlStringParam = new CodeArgumentReferenceExpression("xml"); var objParam = new CodeDirectionExpression( FieldDirection.Out, new CodeFieldReferenceExpression(null, "obj")); var expParam = new CodeDirectionExpression( FieldDirection.Out, new CodeFieldReferenceExpression(null, "exception")); deserializeInvoke = new CodeMethodInvokeExpression( new CodeMethodReferenceExpression(null, GeneratorContext.GeneratorParams.DeserializeMethodName), new CodeExpression[] { xmlStringParam, objParam, expParam }); var returnStmt = new CodeMethodReturnStatement(deserializeInvoke); deserializeMethod.Statements.Add(returnStmt); deserializeMethodList.Add(deserializeMethod); return deserializeMethodList.ToArray(); } /// /// Gets the save to file code DOM method. /// /// /// return the save to file code DOM method statment /// protected virtual CodeMemberMethod GetSaveToFileMethod() { // ----------------------------------------------- // public virtual void SaveToFile(string fileName) // ----------------------------------------------- var saveToFileMethod = new CodeMemberMethod { Attributes = MemberAttributes.Public, Name = GeneratorContext.GeneratorParams.SaveToFileMethodName }; saveToFileMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "fileName")); saveToFileMethod.Statements.Add( new CodeVariableDeclarationStatement( new CodeTypeReference(typeof(StreamWriter)), "streamWriter", new CodePrimitiveExpression(null))); // ------------------------ // try {...} finally {...} // ----------------------- var tryExpression = new CodeStatementCollection(); // ------------------------------ // string xmlString = Serialize(); // ------------------------------- var serializeMethodInvoke = new CodeMethodInvokeExpression( new CodeMethodReferenceExpression(null, GeneratorContext.GeneratorParams.SerializeMethodName)); var xmlString = new CodeVariableDeclarationStatement( new CodeTypeReference(typeof(string)), "xmlString", serializeMethodInvoke); tryExpression.Add(xmlString); // -------------------------------------------------------------- // System.IO.FileInfo xmlFile = new System.IO.FileInfo(fileName); // -------------------------------------------------------------- tryExpression.Add(CodeDomHelper.CreateObject(typeof(FileInfo), "xmlFile", new[] { "fileName" })); // ---------------------------------------- // StreamWriter Tex = xmlFile.CreateText(); // ---------------------------------------- var createTextMethodInvoke = CodeDomHelper.GetInvokeMethod("xmlFile", "CreateText"); tryExpression.Add( new CodeAssignStatement( new CodeVariableReferenceExpression("streamWriter"), createTextMethodInvoke)); // ---------------------------------- // streamWriter.WriteLine(xmlString); // ---------------------------------- var writeLineMethodInvoke = CodeDomHelper.GetInvokeMethod( "streamWriter", "WriteLine", new CodeExpression[] { new CodeVariableReferenceExpression("xmlString") }); tryExpression.Add(writeLineMethodInvoke); var closeMethodInvoke = CodeDomHelper.GetInvokeMethod("streamWriter", "Close"); tryExpression.Add(closeMethodInvoke); var finallyStatmanentsCol = new CodeStatementCollection(); finallyStatmanentsCol.Add(CodeDomHelper.GetDispose("streamWriter")); var trycatch = new CodeTryCatchFinallyStatement(tryExpression.ToArray(), new CodeCatchClause[0], finallyStatmanentsCol.ToArray()); saveToFileMethod.Statements.Add(trycatch); return saveToFileMethod; } /// /// Gets the save to file code DOM method. /// /// CodeTypeDeclaration type. /// /// return the save to file code DOM method statment /// protected virtual CodeMemberMethod[] GetOverrideSaveToFileMethods(CodeTypeDeclaration type) { var saveToFileMethodList = new List(); var saveToFileMethod = new CodeMemberMethod { Attributes = MemberAttributes.Public, Name = GeneratorContext.GeneratorParams.SaveToFileMethodName }; saveToFileMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "fileName")); var paramException = new CodeParameterDeclarationExpression( typeof(Exception), "exception") { Direction = FieldDirection.Out }; saveToFileMethod.Parameters.Add(paramException); saveToFileMethod.ReturnType = new CodeTypeReference(typeof(bool)); saveToFileMethod.Statements.Add( new CodeAssignStatement(new CodeArgumentReferenceExpression("exception"), new CodePrimitiveExpression(null))); // --------------------- // try {...} catch {...} // --------------------- var tryExpression = new CodeStatementCollection(); // --------------------- // SaveToFile(fileName); // --------------------- var xmlStringParam = new CodeArgumentReferenceExpression("fileName"); var saveToFileInvoke = new CodeMethodInvokeExpression( new CodeMethodReferenceExpression(null, GeneratorContext.GeneratorParams.SaveToFileMethodName), new CodeExpression[] { xmlStringParam }); tryExpression.Add(saveToFileInvoke); tryExpression.Add(CodeDomHelper.GetReturnTrue()); // ----------- // Catch {...} // ----------- var catchstmts = new CodeStatementCollection(); catchstmts.Add(new CodeAssignStatement(new CodeArgumentReferenceExpression("exception"), new CodeVariableReferenceExpression("e"))); catchstmts.Add(CodeDomHelper.GetReturnFalse()); var codeCatchClause = new CodeCatchClause("e", new CodeTypeReference(typeof(Exception)), catchstmts.ToArray()); var codeCatchClauses = new[] { codeCatchClause }; var trycatch = new CodeTryCatchFinallyStatement(tryExpression.ToArray(), codeCatchClauses); saveToFileMethod.Statements.Add(trycatch); saveToFileMethod.Comments.AddRange( CodeDomHelper.GetSummaryComment(string.Format("Serializes current {0} object into file", type.Name))); saveToFileMethod.Comments.Add(CodeDomHelper.GetParamComment("fileName", "full path of outupt xml file")); saveToFileMethod.Comments.Add(CodeDomHelper.GetParamComment("exception", "output Exception value if failed")); saveToFileMethod.Comments.Add(CodeDomHelper.GetReturnComment("true if can serialize and save into file; otherwise, false")); saveToFileMethodList.Add(saveToFileMethod); return saveToFileMethodList.ToArray(); } /// /// Gets the load from file CodeDOM method. /// /// The type CodeTypeDeclaration. /// return the codeDom LoadFromFile method protected virtual CodeMemberMethod GetLoadFromFileMethod(CodeTypeDeclaration type) { string typeName = GeneratorContext.GeneratorParams.UseGenericBaseClass ? "T" : type.Name; // --------------------------------------------- // public static T LoadFromFile(string fileName) // --------------------------------------------- var loadFromFileMethod = new CodeMemberMethod { Attributes = MemberAttributes.Public | MemberAttributes.Static, Name = GeneratorContext.GeneratorParams.LoadFromFileMethodName }; loadFromFileMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "fileName")); loadFromFileMethod.ReturnType = new CodeTypeReference(typeName); loadFromFileMethod.Statements.Add( new CodeVariableDeclarationStatement( new CodeTypeReference(typeof(FileStream)), "file", new CodePrimitiveExpression(null))); loadFromFileMethod.Statements.Add( new CodeVariableDeclarationStatement( new CodeTypeReference(typeof(StreamReader)), "sr", new CodePrimitiveExpression(null))); var tryStatmanentsCol = new CodeStatementCollection(); var finallyStatmanentsCol = new CodeStatementCollection(); // --------------------------------------------------------------------------- // file = new FileStream(fileName, FileMode.Open, FileAccess.Read); // sr = new StreamReader(file); // --------------------------------------------------------------------------- tryStatmanentsCol.Add( new CodeAssignStatement( new CodeVariableReferenceExpression("file"), new CodeObjectCreateExpression( typeof(FileStream), new CodeExpression[] { new CodeArgumentReferenceExpression("fileName"), CodeDomHelper.GetEnum("FileMode","Open"), CodeDomHelper.GetEnum("FileAccess","Read") }))); tryStatmanentsCol.Add( new CodeAssignStatement( new CodeVariableReferenceExpression("sr"), new CodeObjectCreateExpression( typeof(StreamReader), new CodeExpression[] { new CodeVariableReferenceExpression("file"), }))); // ---------------------------------- // string xmlString = sr.ReadToEnd(); // ---------------------------------- var readToEndInvoke = CodeDomHelper.GetInvokeMethod("sr", "ReadToEnd"); var xmlString = new CodeVariableDeclarationStatement( new CodeTypeReference(typeof(string)), "xmlString", readToEndInvoke); tryStatmanentsCol.Add(xmlString); tryStatmanentsCol.Add(CodeDomHelper.GetInvokeMethod("sr", "Close")); tryStatmanentsCol.Add(CodeDomHelper.GetInvokeMethod("file", "Close")); // ------------------------------------------------------ // return Deserialize(xmlString, out obj, out exception); // ------------------------------------------------------ var fileName = new CodeVariableReferenceExpression("xmlString"); var deserializeInvoke = new CodeMethodInvokeExpression( new CodeMethodReferenceExpression(null, GeneratorContext.GeneratorParams.DeserializeMethodName), new CodeExpression[] { fileName }); var rstmts = new CodeMethodReturnStatement(deserializeInvoke); tryStatmanentsCol.Add(rstmts); finallyStatmanentsCol.Add(CodeDomHelper.GetDispose("file")); finallyStatmanentsCol.Add(CodeDomHelper.GetDispose("sr")); var tryfinally = new CodeTryCatchFinallyStatement( CodeDomHelper.CodeStmtColToArray(tryStatmanentsCol), new CodeCatchClause[0], CodeDomHelper.CodeStmtColToArray(finallyStatmanentsCol)); loadFromFileMethod.Statements.Add(tryfinally); return loadFromFileMethod; } /// /// Gets the load from file CodeDOM method. /// /// The type CodeTypeDeclaration. /// return the codeDom LoadFromFile method protected virtual CodeMemberMethod[] GetOverrideLoadFromFileMethods(CodeTypeDeclaration type) { string typeName = GeneratorContext.GeneratorParams.UseGenericBaseClass ? "T" : type.Name; CodeTypeReference teeType = new CodeTypeReference(typeName); var saveToFileMethodList = new List(); var loadFromFileMethod = new CodeMemberMethod { Attributes = MemberAttributes.Public | MemberAttributes.Static, Name = GeneratorContext.GeneratorParams.LoadFromFileMethodName }; loadFromFileMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "fileName")); var param = new CodeParameterDeclarationExpression(typeName, "obj") { Direction = FieldDirection.Out }; loadFromFileMethod.Parameters.Add(param); param = new CodeParameterDeclarationExpression(typeof(Exception), "exception") { Direction = FieldDirection.Out }; loadFromFileMethod.Parameters.Add(param); loadFromFileMethod.ReturnType = new CodeTypeReference(typeof(bool)); // ----------------- // exception = null; // obj = null; // ----------------- loadFromFileMethod.Statements.Add( new CodeAssignStatement(new CodeArgumentReferenceExpression("exception"), new CodePrimitiveExpression(null))); loadFromFileMethod.Statements.Add( new CodeAssignStatement(new CodeArgumentReferenceExpression("obj"), new CodeDefaultValueExpression(teeType))); var tryStatmanentsCol = new CodeStatementCollection(); // Call LoadFromFile method var loadFromFileInvoke = new CodeMethodInvokeExpression( new CodeMethodReferenceExpression(null, GeneratorContext.GeneratorParams.LoadFromFileMethodName), new CodeExpression[] { new CodeArgumentReferenceExpression("fileName") }); tryStatmanentsCol.Add( new CodeAssignStatement( new CodeArgumentReferenceExpression("obj"), loadFromFileInvoke)); tryStatmanentsCol.Add(CodeDomHelper.GetReturnTrue()); var trycatch = new CodeTryCatchFinallyStatement( CodeDomHelper.CodeStmtColToArray(tryStatmanentsCol), CodeDomHelper.GetCatchClause()); loadFromFileMethod.Statements.Add(trycatch); loadFromFileMethod.Comments.AddRange( CodeDomHelper.GetSummaryComment( string.Format("Deserializes xml markup from file into an {0} object", type.Name))); loadFromFileMethod.Comments.Add(CodeDomHelper.GetParamComment("fileName", "string xml file to load and deserialize")); loadFromFileMethod.Comments.Add(CodeDomHelper.GetParamComment("obj", string.Format("Output {0} object", type.Name))); loadFromFileMethod.Comments.Add(CodeDomHelper.GetParamComment("exception", "output Exception value if deserialize failed")); loadFromFileMethod.Comments.Add( CodeDomHelper.GetReturnComment("true if this XmlSerializer can deserialize the object; otherwise, false")); saveToFileMethodList.Add(loadFromFileMethod); // ------------------------------------------------------ // public static bool LoadFromFile(string xml, out T obj) // ------------------------------------------------------ loadFromFileMethod = new CodeMemberMethod { Attributes = MemberAttributes.Public | MemberAttributes.Static, Name = GeneratorContext.GeneratorParams.LoadFromFileMethodName }; loadFromFileMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "fileName")); loadFromFileMethod.ReturnType = new CodeTypeReference(typeof(bool)); param = new CodeParameterDeclarationExpression(typeName, "obj") { Direction = FieldDirection.Out }; loadFromFileMethod.Parameters.Add(param); // --------------------------- // Exception exception = null; // --------------------------- loadFromFileMethod.Statements.Add( new CodeVariableDeclarationStatement(typeof(Exception), "exception", new CodePrimitiveExpression(null))); // ------------------------------------------------------ // return LoadFromFile(fileName, out obj, out exception); // ------------------------------------------------------ var fileName = new CodeArgumentReferenceExpression("fileName"); var objParam = new CodeDirectionExpression( FieldDirection.Out, new CodeFieldReferenceExpression(null, "obj")); var expParam = new CodeDirectionExpression( FieldDirection.Out, new CodeFieldReferenceExpression(null, "exception")); var loadFromFileMethodInvok = new CodeMethodInvokeExpression( new CodeMethodReferenceExpression(null, GeneratorContext.GeneratorParams.LoadFromFileMethodName), new CodeExpression[] { fileName, objParam, expParam }); var returnStmt = new CodeMethodReturnStatement(loadFromFileMethodInvok); loadFromFileMethod.Statements.Add(returnStmt); saveToFileMethodList.Add(loadFromFileMethod); return saveToFileMethodList.ToArray(); } /// /// Import namespaces /// /// Code namespace protected virtual void ImportNamespaces(CodeNamespace code) { code.Imports.Add(new CodeNamespaceImport("System")); code.Imports.Add(new CodeNamespaceImport("System.Diagnostics")); code.Imports.Add(new CodeNamespaceImport("System.Xml.Serialization")); code.Imports.Add(new CodeNamespaceImport("System.Collections")); code.Imports.Add(new CodeNamespaceImport("System.Xml.Schema")); code.Imports.Add(new CodeNamespaceImport("System.ComponentModel")); if (GeneratorContext.GeneratorParams.CustomUsings != null) { foreach (var item in GeneratorContext.GeneratorParams.CustomUsings) code.Imports.Add(new CodeNamespaceImport(item.NameSpace)); } if (GeneratorContext.GeneratorParams.IncludeSerializeMethod) code.Imports.Add(new CodeNamespaceImport("System.IO")); switch (GeneratorContext.GeneratorParams.CollectionObjectType) { case CollectionType.List: code.Imports.Add(new CodeNamespaceImport("System.Collections.Generic")); break; case CollectionType.ObservableCollection: code.Imports.Add(new CodeNamespaceImport("System.Collections.ObjectModel")); break; default: break; } code.Name = GeneratorContext.GeneratorParams.NameSpace; } /// /// Create data contract attribute /// /// Code type declaration /// XML schema protected virtual void CreateDataContractAttribute(CodeTypeDeclaration type, XmlSchema schema) { // abstract } /// /// Creates the data member attribute. /// /// Represents a declaration for a property of a type. protected virtual void CreateDataMemberAttribute(CodeMemberProperty prop) { // abstract } /// /// Recursive search of elemement. /// /// Element to search /// Current element /// Name of the current element. /// The hierarchical Elmt Name. /// /// return found XmlSchemaElement or null value /// protected virtual XmlSchemaElement SearchElement(CodeTypeDeclaration type, XmlSchemaElement xmlElement, string currentElementName, string hierarchicalElmtName) { var found = false; if (type.IsClass) { if (xmlElement.Name == null) return null; if (type.Name.Equals(hierarchicalElmtName + xmlElement.Name) || type.Name.Equals(xmlElement.Name)) found = true; } else { if (type.Name.Equals(xmlElement.QualifiedName.Name)) found = true; } if (found) return xmlElement; var xmlComplexType = xmlElement.ElementSchemaType as XmlSchemaComplexType; if (xmlComplexType != null) { var xmlSequence = xmlComplexType.ContentTypeParticle as XmlSchemaSequence; if (xmlSequence != null) { foreach (XmlSchemaObject item in xmlSequence.Items) { var currentXmlSchemaElement = item as XmlSchemaElement; if (currentXmlSchemaElement == null) continue; if (hierarchicalElmtName == xmlElement.QualifiedName.Name || currentElementName == xmlElement.QualifiedName.Name) return null; XmlSchemaElement subItem = this.SearchElement( type, currentXmlSchemaElement, xmlElement.QualifiedName.Name, hierarchicalElmtName + xmlElement.QualifiedName.Name); if (subItem != null) return subItem; } } } return null; } /// /// Create CodeCommentStatement from schema documentation. /// /// CodeCommentStatementCollection collection /// Schema documentation protected virtual void CreateCommentStatment( CodeCommentStatementCollection codeStatmentColl, XmlSchemaDocumentation xmlDoc) { codeStatmentColl.Clear(); foreach (XmlNode itemDoc in xmlDoc.Markup) { var textLine = itemDoc.InnerText.Trim(); if (textLine.Length > 0) CodeDomHelper.CreateSummaryComment(codeStatmentColl, textLine); } } /// /// Field process. /// /// CodeTypeMember member /// CodeMemberMethod constructor /// CodeNamespace XSD /// Indicates if create a new constructor protected virtual void ProcessFields( CodeTypeMember member, CodeMemberMethod ctor, CodeNamespace ns, ref bool addedToConstructor) { var field = (CodeMemberField)member; // --------------------------------------------- // [EditorBrowsable(EditorBrowsableState.Never)] // --------------------------------------------- if (member.Attributes == MemberAttributes.Private) { if (GeneratorContext.GeneratorParams.HidePrivateFieldInIde) { var attributeType = new CodeTypeReference( typeof(EditorBrowsableAttribute).Name.Replace("Attribute", string.Empty)); var argument = new CodeAttributeArgument { //Value = new CodePropertyReferenceExpression( //new CodeSnippetExpression(typeof(EditorBrowsableState).Name), "Never") Value = CodeDomHelper.GetEnum(typeof(EditorBrowsableState).Name,"Never") }; field.CustomAttributes.Add(new CodeAttributeDeclaration(attributeType, new[] { argument })); } } // ------------------------------------------ // protected virtual List nameField; // ------------------------------------------ var thisIsCollectionType = field.Type.ArrayElementType != null; if (thisIsCollectionType) { field.Type = this.GetCollectionType(field.Type); } // --------------------------------------- // if ((this.nameField == null)) // { // this.nameField = new List(); // } // --------------------------------------- if (GeneratorContext.GeneratorParams.EnableInitializeFields && GeneratorContext.GeneratorParams.CollectionObjectType != CollectionType.Array) { CodeTypeDeclaration declaration = this.FindTypeInNamespace(field.Type.BaseType, ns); if (thisIsCollectionType || (((declaration != null) && declaration.IsClass) && ((declaration.TypeAttributes & TypeAttributes.Abstract) != TypeAttributes.Abstract))) { if (GeneratorContext.GeneratorParams.EnableLasyLoading) { lasyLoadingFields.Add(field.Name); } else { ctor.Statements.Insert(0, this.CreateInstance(field.Name, field.Type)); addedToConstructor = true; } } } } /// /// Create a Class Constructor /// /// type of declaration /// return CodeConstructor protected virtual CodeConstructor CreateClassConstructor(CodeTypeDeclaration type) { var ctor = new CodeConstructor { Attributes = MemberAttributes.Public, Name = type.Name }; return ctor; } /// /// Create new instance of object /// /// Name of object /// CodeTypeReference Type /// return instance CodeConditionStatement protected virtual CodeConditionStatement CreateInstanceIfNotNull(string name, CodeTypeReference type) { CodeAssignStatement statement; if (type.BaseType.Equals("System.String") && type.ArrayRank == 0) { statement = new CodeAssignStatement( new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), name), //new CodeSnippetExpression("String.Empty")); CodeDomHelper.GetStaticField(typeof(String), "Empty")); } else{ statement = new CodeAssignStatement( new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), name), new CodeObjectCreateExpression(type, new CodeExpression[0])); } return new CodeConditionStatement( new CodeBinaryOperatorExpression( new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), name), CodeBinaryOperatorType.IdentityEquality, new CodePrimitiveExpression(null)), new CodeStatement[] { statement }); } /// /// Create new instance of object /// /// Name of object /// CodeTypeReference Type /// return instance CodeConditionStatement protected virtual CodeAssignStatement CreateInstance(string name, CodeTypeReference type) { //return new CodeAssignStatement( // new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), name), // new CodeObjectCreateExpression(type, new CodeExpression[0])); CodeAssignStatement statement; if (type.BaseType.Equals("System.String") && type.ArrayRank == 0) { statement = new CodeAssignStatement( new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), name), //new CodeSnippetExpression("String.Empty")); CodeDomHelper.GetStaticField(typeof(String), "Empty")); } else { statement = new CodeAssignStatement( new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), name), new CodeObjectCreateExpression(type, new CodeExpression[0])); } return statement; } /// /// Recherche le CodeTypeDeclaration d'un objet en fonction de son type de base (nom de classe) /// /// Search name /// Seach into /// CodeTypeDeclaration found protected virtual CodeTypeDeclaration FindTypeInNamespace(string typeName, CodeNamespace ns) { foreach (CodeTypeDeclaration declaration in ns.Types) { if (declaration.Name == typeName) return declaration; } return null; } /// /// 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 virtual void ProcessProperty(CodeTypeDeclaration type, CodeNamespace ns, CodeTypeMember member, XmlSchemaElement xmlElement, XmlSchema schema) { if (GeneratorContext.GeneratorParams.EnableSummaryComment) { if (xmlElement != null) { var xmlComplexType = xmlElement.ElementSchemaType as XmlSchemaComplexType; bool foundInAttributes = false; if (xmlComplexType != null) { // Search property in attributes for summary comment generation foreach (XmlSchemaObject attribute in xmlComplexType.Attributes) { var xmlAttrib = attribute as XmlSchemaAttribute; if (xmlAttrib != null) { if (member.Name.Equals(xmlAttrib.QualifiedName.Name)) { this.CreateCommentFromAnnotation(xmlAttrib.Annotation, member.Comments); foundInAttributes = true; } } } // Search property in XmlSchemaElement for summary comment generation if (!foundInAttributes) { var xmlSequence = xmlComplexType.ContentTypeParticle as XmlSchemaSequence; if (xmlSequence != null) { foreach (XmlSchemaObject item in xmlSequence.Items) { var currentItem = item as XmlSchemaElement; if (currentItem != null) { if (member.Name.Equals(currentItem.QualifiedName.Name)) this.CreateCommentFromAnnotation(currentItem.Annotation, member.Comments); } } } } } } } var prop = (CodeMemberProperty)member; if (prop.Type.ArrayElementType != null) { prop.Type = this.GetCollectionType(prop.Type); collectionTypesFields.Add(prop.Name); } if (GeneratorContext.GeneratorParams.GenerateDataContracts) { this.CreateDataMemberAttribute(prop); } // Lasy loading if (GeneratorContext.GeneratorParams.EnableInitializeFields) { var propReturnStatment = prop.GetStatements[0] as CodeMethodReturnStatement; if (propReturnStatment != null) { var field = propReturnStatment.Expression as CodeFieldReferenceExpression; if (field != null) { if (lasyLoadingFields.IndexOf(field.FieldName) != -1) { prop.GetStatements.Insert(0, this.CreateInstanceIfNotNull(field.FieldName, prop.Type)); } } } } // Add OnPropertyChanged in setter if (GeneratorContext.GeneratorParams.EnableDataBinding) { if (type.BaseTypes.IndexOf(new CodeTypeReference(typeof(CollectionBase))) == -1) { // ----------------------------- // if (handler != null) { // OnPropertyChanged("Name"); // ----------------------------- var propChange = new CodeMethodInvokeExpression( new CodeMethodReferenceExpression(new CodeThisReferenceExpression(), "OnPropertyChanged"), new CodeExpression[] { new CodePrimitiveExpression( prop.Name ) }); var propAssignStatment = prop.SetStatements[0] as CodeAssignStatement; if (propAssignStatment != null) { var cfreL = propAssignStatment.Left as CodeFieldReferenceExpression; var cfreR = propAssignStatment.Right as CodePropertySetValueReferenceExpression; if (cfreL != null) { var setValueCondition = new CodeStatementCollection { propAssignStatment, propChange }; // --------------------------------------------- // if ((xxxField.Equals(value) != true)) { ... } // --------------------------------------------- var condStatmentCondEquals = new CodeConditionStatement( new CodeBinaryOperatorExpression( new CodeMethodInvokeExpression( new CodeFieldReferenceExpression( null, cfreL.FieldName), "Equals", cfreR), CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(true)), CodeDomHelper.CodeStmtColToArray(setValueCondition)); // --------------------------------------------- // if ((xxxField != null)) { ... } // --------------------------------------------- var condStatmentCondNotNull = new CodeConditionStatement( new CodeBinaryOperatorExpression( new CodeFieldReferenceExpression( new CodeThisReferenceExpression(), cfreL.FieldName), CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(null)), new CodeStatement[] { condStatmentCondEquals }, CodeDomHelper.CodeStmtColToArray(setValueCondition)); var property = member as CodeMemberProperty; if (property != null) { if (property.Type.BaseType != new CodeTypeReference(typeof(long)).BaseType && property.Type.BaseType != new CodeTypeReference(typeof(DateTime)).BaseType && property.Type.BaseType != new CodeTypeReference(typeof(float)).BaseType && property.Type.BaseType != new CodeTypeReference(typeof(double)).BaseType && property.Type.BaseType != new CodeTypeReference(typeof(int)).BaseType && property.Type.BaseType != new CodeTypeReference(typeof(bool)).BaseType && enumListField.IndexOf(property.Type.BaseType) == -1) prop.SetStatements[0] = condStatmentCondNotNull; else prop.SetStatements[0] = condStatmentCondEquals; } } else prop.SetStatements.Add(propChange); } } } } /// /// Determines whether [is complex type] [the specified code type reference]. /// /// Name of the field. /// The code type reference. /// The ns. /// /// true if type is complex type (class, List, etc.)"/> /// protected bool IsComplexType(CodeTypeReference codeTypeReference, CodeNamespace ns) { CodeTypeDeclaration declaration = this.FindTypeInNamespace(codeTypeReference.BaseType, ns); return ((declaration != null) && declaration.IsClass) && ((declaration.TypeAttributes & TypeAttributes.Abstract) != TypeAttributes.Abstract); } /// /// Removes the default XML attributes. /// /// /// The custom Attributes. /// protected virtual void RemoveDefaultXmlAttributes(CodeAttributeDeclarationCollection customAttributes) { var codeAttributes = new List(); foreach (var attribute in customAttributes) { var attrib = attribute as CodeAttributeDeclaration; if (attrib == null) { continue; } if (attrib.Name == "System.Xml.Serialization.XmlAttributeAttribute" || attrib.Name == "System.Xml.Serialization.XmlIgnoreAttribute" || attrib.Name == "System.Xml.Serialization.XmlTypeAttribute" || attrib.Name == "System.Xml.Serialization.XmlElementAttribute" || attrib.Name == "System.CodeDom.Compiler.GeneratedCodeAttribute" || attrib.Name == "System.Xml.Serialization.XmlRootAttribute") { codeAttributes.Add(attrib); } } foreach (var item in codeAttributes) { customAttributes.Remove(item); } } /// /// Removes the debug attributes. /// /// The custom attributes Collection. protected virtual void RemoveDebugAttributes(CodeAttributeDeclarationCollection customAttributes) { var codeAttributes = new List(); foreach (var attribute in customAttributes) { var attrib = attribute as CodeAttributeDeclaration; if (attrib == null) { continue; } if (attrib.Name == "System.Diagnostics.DebuggerStepThroughAttribute") { codeAttributes.Add(attrib); } } //DCM: OK not sure why it in this loop other than its like a transaction. //Not going to touch it now. foreach (var item in codeAttributes) { customAttributes.Remove(item); } } /// /// Generate summary comment from XmlSchemaAnnotation /// /// XmlSchemaAnnotation from XmlSchemaElement or XmlSchemaAttribute /// codeCommentStatementCollection from member protected virtual void CreateCommentFromAnnotation(XmlSchemaAnnotation xmlSchemaAnnotation, CodeCommentStatementCollection codeCommentStatementCollection) { if (xmlSchemaAnnotation != null) { foreach (XmlSchemaObject annotation in xmlSchemaAnnotation.Items) { var xmlDoc = annotation as XmlSchemaDocumentation; if (xmlDoc != null) { this.CreateCommentStatment(codeCommentStatementCollection, xmlDoc); } } } } /// /// Get CodeTypeReference for collection /// /// The code Type. /// return array of or genereric collection protected virtual CodeTypeReference GetCollectionType(CodeTypeReference codeType) { CodeTypeReference collectionType = codeType; if (codeType.BaseType == typeof(byte).FullName) { // Never change byte[] to List etc. // Fix : when translating hexBinary and base64Binary return codeType; } switch (GeneratorContext.GeneratorParams.CollectionObjectType) { case CollectionType.List: collectionType = new CodeTypeReference("List", new[] { new CodeTypeReference(codeType.BaseType) }); break; case CollectionType.BindingList: collectionType = new CodeTypeReference("BindingList", new[] { new CodeTypeReference(codeType.BaseType) }); break; case CollectionType.ObservableCollection: collectionType = new CodeTypeReference("ObservableCollection", new[] { new CodeTypeReference(codeType.BaseType) }); break; case CollectionType.DefinedType: string typname = codeType.BaseType.Replace(".", string.Empty) + "Collection"; if (!CollectionTypes.Keys.Contains(typname)) CollectionTypes.Add(typname, codeType.BaseType); collectionType = new CodeTypeReference(typname); break; default: { // If not use generics, remove multiple array Ex. string[][] => string[] // Fix : http://xsd2code.codeplex.com/WorkItem/View.aspx?WorkItemId=7269 if (codeType.ArrayElementType.ArrayRank > 0) collectionType.ArrayElementType.ArrayRank = 0; } break; } return collectionType; } /// /// Search defaut constructor. If not exist, create a new ctor. /// /// CodeTypeDeclaration type /// Indicates if new constructor /// return current or new CodeConstructor protected virtual CodeConstructor GetConstructor(CodeTypeDeclaration type, ref bool newCTor) { CodeConstructor ctor = null; foreach (CodeTypeMember member in type.Members) { if (member is CodeConstructor) ctor = member as CodeConstructor; } if (ctor == null) { newCTor = true; ctor = this.CreateClassConstructor(type); } if (GeneratorContext.GeneratorParams.EnableSummaryComment) CodeDomHelper.CreateSummaryComment(ctor.Comments, string.Format("{0} class constructor", ctor.Name)); return ctor; } #endregion #region Private methods /// /// Creates the static serializer. /// /// Type of the class. private static void CreateStaticSerializer(CodeTypeDeclaration classType) { string typeName = GeneratorContext.GeneratorParams.UseGenericBaseClass ? "T" : classType.Name; //VB is not Case Sensitive string fieldName = GeneratorContext.GeneratorParams.Language == GenerationLanguage.VisualBasic ? "sSerializer" : "serializer" ; // ----------------------------------------------------------------- // private static System.Xml.Serialization.XmlSerializer serializer; // ----------------------------------------------------------------- var serializerfield = new CodeMemberField(typeof(XmlSerializer), fieldName); serializerfield.Attributes = MemberAttributes.Static | MemberAttributes.Private; classType.Members.Add(serializerfield); var typeRef = new CodeTypeReference(typeName); var typeofValue = new CodeTypeOfExpression(typeRef); // private static System.Xml.Serialization.XmlSerializer Serializer { get {...} } var serializerProperty = new CodeMemberProperty(); serializerProperty.Type = new CodeTypeReference(typeof(XmlSerializer)); serializerProperty.Name = "Serializer"; serializerProperty.HasSet = false; serializerProperty.HasGet = true; serializerProperty.Attributes = MemberAttributes.Static | MemberAttributes.Private; var statments = new CodeStatementCollection(); statments.Add( new CodeAssignStatement( new CodeVariableReferenceExpression(fieldName), new CodeObjectCreateExpression( new CodeTypeReference(typeof(XmlSerializer)), new CodeExpression[] { typeofValue }))); serializerProperty.GetStatements.Add( new CodeConditionStatement( new CodeBinaryOperatorExpression( new CodeVariableReferenceExpression(fieldName), CodeBinaryOperatorType.IdentityEquality, new CodePrimitiveExpression(null)), statments.ToArray())); serializerProperty.GetStatements.Add( new CodeMethodReturnStatement(new CodeVariableReferenceExpression(fieldName))); classType.Members.Add(serializerProperty); } /// /// Generates the base class. /// /// Return base class codetype declaration private CodeTypeDeclaration GenerateBaseClass() { var baseClass = new CodeTypeDeclaration(GeneratorContext.GeneratorParams.BaseClassName) { IsClass = true, IsPartial = true, TypeAttributes = TypeAttributes.Public }; baseClass.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Base entity class")); baseClass.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, "Base entity class")); if (GeneratorContext.GeneratorParams.EnableDataBinding) baseClass.BaseTypes.Add(typeof(INotifyPropertyChanged)); baseClass.TypeParameters.Add(new CodeTypeParameter("T")); if (GeneratorContext.GeneratorParams.EnableDataBinding) this.CreateDataBinding(baseClass); if (GeneratorContext.GeneratorParams.IncludeSerializeMethod) { CreateStaticSerializer(baseClass); this.CreateSerializeMethods(baseClass); } if (GeneratorContext.GeneratorParams.GenerateCloneMethod) this.CreateCloneMethod(baseClass); return baseClass; } /// /// Search XmlElement in schema. /// /// Represents a type declaration for a class, structure, interface, or enumeration. /// schema object /// The visited schemas. /// /// return found XmlSchemaElement or null value /// private XmlSchemaElement SearchElementInSchema(CodeTypeDeclaration codeTypeDeclaration, XmlSchema schema, List visitedSchemas) { foreach (var item in schema.Items) { var xmlElement = item as XmlSchemaElement; if (xmlElement == null) { continue; } var xmlSubElement = this.SearchElement(codeTypeDeclaration, xmlElement, string.Empty, string.Empty); if (xmlSubElement != null) return xmlSubElement; } // If not found search in schema inclusion foreach (var item in schema.Includes) { var schemaInc = item as XmlSchemaInclude; // avoid to follow cyclic refrence if ((schemaInc == null) || visitedSchemas.Exists(loc => schemaInc.Schema == loc)) continue; visitedSchemas.Add(schemaInc.Schema); var includeElmts = this.SearchElementInSchema(codeTypeDeclaration, schemaInc.Schema, visitedSchemas); visitedSchemas.Remove(schemaInc.Schema); if (includeElmts != null) return includeElmts; } return null; } #endregion } }