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