NAVmoble - the pocket-sized ERP
Optimized for Microsoft Dynamics NAV and Windows Mobile powered devices

Sunday, July 17, 2005

C# Code Generation with .NET - part 1

Code generation tools are already standard equipment for the
developers these days.
The main motivation to use code generation techniques is that
most of theprojects share similar development tasks. It is
possibleto automate the execution these tasks by using special
tools -code generators.
The sample proposed here demonstrates some .NET features
for language independent code generation. The sample its self
should not be considered as a complete code generator
architecture.The development scenario, automated in this
sample is whenthe developer have a sample xml file, which
should be deserializedas a native .NET class , processed
somehow and serialized back to xml content.
The sample implements a class called XmlCodeGenerator,
which generates C# source files from given Xml file.Each
generated source file contains a C# class for each unique xml
element contained in the xml file. It automatically recognize if
the xml element should be mapped to as class or class member.
Due to the missing information about the actual data types all
xml elements mapped to simlpe class members are implemented
as System.String. Generated classes may be compiled and used
with System.Xml.Serialization.XmlSerializer class

If we have the following xml file:

<?xml version="1.0" encoding="utf-8" ?>
<employee memberOf="Managers">
<address>1000 Mladost</address>

XmlCodeGenerator will map the xml content to 3 classes in the
following way:

Xml element.NET class

The rest of the elements and attributes within the xml content
will be mapped as class members

This core functionality is wrapped around the System.CodeDom
name space. In general it contains classes that can be used to
represent the elements and structure of a source code document.
In order to create a .NET class declaration for the root xml element
"employeeList" we will have the following code:

uses Microsoft.CSharp;
uses System.CodeDom;
uses System.CodeDom.Compiler;
CodeTypeDeclaration classDeclaration = new CodeTypeDeclaration("EmployeeList");
classDeclaration.IsClass = true;
//make it public
constructor.Attributes= MemberAttributes.Public;
//add constructor
CodeConstructor constructor =
new CodeConstructor();
//add class level XmlRoot attribute
classDeclaration.CustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlRoot",new CodeAttributeArgument(new CodePrimitiveExpression("employeeList"))));

Next, we should add some class members. In our case
"employeeList" element has one sub-element named
"emlpoyee". It will appear as a class member called Employee
of type Employee. The following code may be used to create
this class member:

uses Microsoft.CSharp;
uses System.CodeDom;
uses System.CodeDom.Compiler;
//create field
CodeMemberField field = new CodeMemberField("Employee","m_employee");
//embed field into the class declaration
//create property
CodeMemberProperty property = new CodeMemberProperty();
property.Name = "Employee";
property.Type = new CodeTypeReference("Employee");
property.Attributes = MemberAttributes.Public;
//add XmlElement attribute for serialziation support
property.CustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlElement",new CodeAttributeArgument(new CodePrimitiveExpression("employee"))));
property.HasGet = true;
property.HasSet = true;
property.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),field.Name)));
property.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),field.Name), new CodePropertySetValueReferenceExpression()));
//embed property into the class declaration

Having this class declaration we have to generate the C# code.
We may do it by using the following code:

uses Microsoft.CSharp;
uses System.CodeDom;
uses System.CodeDom.Compiler;
//obtain C# code provider
CSharpCodeProvider provider = new CSharpCodeProvider();
//get the proper code generator
.ICodeGenerator generator = provider.CreateGenerator();
//create namespace to place our class declaration into
CodeNamespace _namespace = new CodeNamespace(Namespace);
//generate code
CodeGeneratorOptions options = new CodeGeneratorOptions();
options.BlankLinesBetweenMembers = true;
System.IO.StreamWriter sw = System.IO.File.CreateText("D:\\work\\employeeList.cs");

As you may see having this type of class declaration our code
generator is not limited to C# code generation only.

Let's wrap up these code snipsets...To be continued

No comments: