Introducing Code Generation - Generating a Simple Class via CodeDOM
(Page 12 of 13 )
Initiating code generation via the CodeDOM requires that you open the XML meta-data document for input and call the ClassViaCodeDOM to create the CodeCompileUnit that contains the CodeDOM graph for the target code. The GenerateClassViaCodeDOM method outputs code for the classes. This example only creates VB .NET code, but you could easily change it to output C# or even J# code:10
*********************
NOTE Don’t be concerned if you feel lost or just don’t understand the CodeDOM at this point. You might never use it in code generation if one of the other approaches better suits your needs. If you’re considering using the CodeDOM, there’s an in-depth section about the CodeDOM in Chapter 3 and Appendix D.
Private Shared Sub GenerateClassViaCodeDOM(ByVal outputDir As String) Dim compileUnit As CodeDom.CodeCompileUnit Dim provider As CodeDom.Compiler.CodeDomProvider
' Open Metadata file Dim xmlMetaData As New Xml.XmlDocument xmlMetaData.Load(IO.Path.Combine(xmlDir, "Metadata.xml"))
' Generate simple class for Cusotmers in Visual Basic using the CodeDOM compileUnit = ClassViaCodeDOM.BuildGraph(xmlMetaData, "Customers") provider = New Microsoft.VisualBasic.VBCodeProvider GenerateViaCodeDOM(IO.Path.Combine(outputDir, "ClassCustomersViaCodeDOM.vb"), _
provider, compileUnit)
' Generate simple class for Orders in Visual Basic using the CodeDOM compileUnit = ClassViaCodeDOM.BuildGraph(xmlMetaData, "Orders") provider = New Microsoft.VisualBasic.VBCodeProvider GenerateViaCodeDOM(IO.Path.Combine(outputDir, "ClassOrdersViaCodeDOM.vb"), _
provider, compileUnit) End Sub
*********************
10. To modify the output language, use the alternate provider as shown in the “Generating ‘Hello World’ via the CodeDOM” section.
A separate method, ClassViaCodeDOM.GenerateGraph, builds the CodeCompileUnit:
' Class Summary: Generates a simple class based on XML metadata Public Class ClassViaCodeDOM
#Region "Public Methods and Properties"
Public Shared Function BuildGraph( _
ByVal xmlMetaData As Xml.XmlDocument, _
ByVal tableName As String) _
As CodeDom.CodeCompileUnit
Creating the compile unit and namespace is similar to the “Hello World” CodeDOM example. The CodeTypeDeclaration creates a class with the name of the underlying table. Creating the node and nodeList variables is similar to the brute-force code generation in the section “Generating a Simple Class via Brute Force.” Filling the node list uses the same XPath expression as the brute-force generation:
Dim node As Xml.XmlNode Dim nodeList As Xml.XmlNodeList Dim compileUnit As New CodeDom.CodeCompileUnit Dim nSpace As CodeDom.CodeNamespace Dim clsTable As CodeDom.CodeTypeDeclaration nodeList = xmlMetaData.SelectNodes( _
"/DataSet/Table[@Name=’" & tableName & "']/Column") nSpace = New CodeDom.CodeNamespace("ClassViaCodeDOM") compileUnit.Namespaces.Add(nSpace)
nSpace.Imports.Add(New CodeDom.CodeNamespaceImport("System"))
clsTable = New CodeDom.CodeTypeDeclaration(tableName) nSpace.Types.Add(clsTable)
The field variable is a CodeMemberField object that represents the private field for each column. Each loop creates a new CodeMemberField object and assigns it to the field variable. The Name and Type attributes of the XML node are also assigned to properties of the field variable. The Type property of the CodeMemberField is set by creating a new CodeTypeReference object that utilizes the Type attribute of the XML. The CodeMemberField object contains an Attributes property that, among other things, holds the scope of the field:
Dim field As CodeDom.CodeMemberField
For Each node In nodeList
field = New CodeDom.CodeMemberField
field.Name = "m_" & node.Attributes("Name").Value
field.Attributes = CodeDom.MemberAttributes.Private field.Type = New CodeDom.CodeTypeReference(node.Attributes("Type").Value) clsTable.Members.Add(field)
Next
You may have to read this twice because the linguistics of explaining the second loop are pretty twisted. For each column, the generating code creates a CodeMemberProperty object and sets several properties on the new CodeMemberProperty object. As in the previous example, the CodeMemberProperty type is set using a new CodeTypeReference object:
Dim prop As CodeDom.CodeMemberProperty Dim statement As CodeDom.CodePropertySetValueReferenceExpression Dim Name As String For Each node In nodeList
prop = New CodeDom.CodeMemberProperty Name = node.Attributes("Name").Value prop.Name = Name prop.Attributes = CodeDom.MemberAttributes.Public prop.Type = New CodeDom.CodeTypeReference(node.Attributes("Type").Value)
The GetStatements collection of the CodeMemberProperty contains the code statements for the Get method. For this property, it’s just a single return statement with a reference expression for the corresponding private field of the current object:
prop.GetStatements.Add(New CodeDom.CodeMethodReturnStatement( _ New CodeDom.CodeFieldReferenceExpression( _ New CodeDom.CodeThisReferenceExpression, "m_" & Name)))
The single statement in the SetStatement collection assigns the reference expression of the corresponding private field onto the passed value, accessed by the CodePropertySetValueReferenceExpression. This also illustrates a rare instance where really, really long method names aid clarity:
prop.SetStatements.Add(New CodeDom.CodeAssignStatement( _ New CodeDom.CodeFieldReferenceExpression( _ New CodeDom.CodeThisReferenceExpression, "m_" & Name), _ New CodeDom.CodePropertySetValueReferenceExpression)) clsTable.Members.Add(prop) Next
Return compileUnit End Function
#End Region
End Class
That’s a lot of code to output a simple class. Not only is it a lot of code, but this code is a lot harder to understand than the brute-force generation of the same class. As in the “Hello World” example using the CodeDOM, this version doesn’t accomplish as much as the brute-force or XSLT generation examples. It avoids the option statements, regions, and vertical whitespace. But it’s effective in doing the job it sets out to do. Given the metadata, you can use this to create a similar class representing any table in any database and in any supported .NET language.
This chapter is from Code Generation in Microsoft .NET by Kathleen Dollard (Apress, 2004, ISBN: 1590591372). Check it out at your favorite bookstore today.
Buy this book now. |
Next: Generating a Simple Class via XSLT Templates >>
More .NET Articles
More By Apress Publishing