Browse DevX
Sign up for e-mail newsletters from DevX


Build Custom Code Generators in C# : Page 3

You don't have to rely on libraries and frameworks to avoid writing repetitive code; instead, learn to generate such code automatically, using a custom input format to describe the code you want to generate.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Example Input and Output
The code below contains several samples of the input XML and the resuting generated code. Notice how the frame around the reading of each of these "property reads" is the same, but the part in the middle varies based on both the type and the cardinality:

Input XML:

<Property> <DeclaringTypeName>Address</DeclaringTypeName> <PropertyName>State</PropertyName> <PropType>Atom</PropType> <AtomicType>String</AtomicType> </Property>

Generated Code:

</i> if (reader.LocalName == "State") { // generated code for 'State' by GeneratePropertyFromXml() readString = reader.ReadString(); if (!string.IsNullOrEmpty(readString)) this.State = readString; continue; }

Input XML:

<Property> <DeclaringTypeName>Address</DeclaringTypeName> <PropertyName>Zip</PropertyName> <PropType>Atom</PropType> <AtomicType>Int32</AtomicType> </Property>

Generated Code:

if (reader.LocalName == "Zip") { // generated code for 'Zip' by GeneratePropertyFromXml() readString = reader.ReadString(); if (!string.IsNullOrEmpty(readString)) this.Zip = XmlConvert.ToInt32(readString); continue; }

Input XML:

<Property> <DeclaringTypeName>Address</DeclaringTypeName> <PropertyName>ArrayDemo</PropertyName> <PropType>ListAtoms</PropType> <AtomicType>Int32</AtomicType> </Property>

Generated Code:

if (reader.LocalName == "ArrayDemo") { // generated code for 'ArrayDemo' by GeneratePropertyFromXml() readString = reader.ReadString(); if (!string.IsNullOrEmpty(readString)) this.ArrayDemo.Add(XmlConvert.ToInt32(readString)); continue; }

For some operations, it doesn't make sense to write entire methods within a function, because each variation will differ only slightly (such as by System.Type or by property name.) Therefore, for these it's best to write short reusable helper methods that return small strings that the calling method can insert into the output. For example, this GetTypeName() function is a helper method that takes a PropertyDefinition as input and returns the .NET type name for the property it represents.

Author's Note: I purposely named the DataType enumerations to match their .NET counterparts. This makes outputting the name a simple conversion to string operation, as you can see in the code pDef.AtomicType.ToString().

private static string GetTypeName(PropertyDefinition pDef) { if (pDef.PropType == PropertyType.Composite || pDef.PropType == PropertyType.ListComposites) { return pDef.CompositeTypeName; } return pDef.AtomicType.ToString(); }

The code near the bottom of the hierarchy of methods generates the actual nitty-gritty output. Because the higher level (more generic) methods pass the IndentingWriter down through each step, all the output will go into the same place in the right order.

static void GenerateReadAtmoicListValue(PropertyDefinition pDef, IndentingWriter tw) { tw.WriteLine("readString = reader.ReadString();"); tw.WriteLine("if(!string.IsNullOrEmpty(readString))"); tw.Indent(); tw.WriteLine("this.{0}.Add({1});", pDef.PropertyName, ConvertAtomFromXml(pDef)); tw.OutDent(); }

The helper method ConvertAtomFromXml in the preceding method is another helper method because, again, this conversion will be very similar for all properties.

The downloadable source includes three test projects: one for testing the generator (TestGenerator.csproj) and another for testing the serialization of the generated classes (TestSerialization.csproj), as well as the example Web service.

Author's Note: In the projects, the two "...ODef.xml" files, AddressODef.xml and PersonODef.xml are marked to be copied to the output directory, so the project code can refer to them without any extra path info. However, the generated output files are coded to go into the Serialization test directory, so if you don't preserve the directory structure of the demo projects, it won't work. It's not apocalyptic, but just be aware that you'll have to modify those directory values to get the demo working if you re-arrange things.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date