August 8th, 2013

This is a quick update for those that use Amazon’s Product Advertising API with C# in the US. Here is an C# enumeration for valid values for SearchIndex.

/// <summary>
/// The possible SearchIndex values for Amazon
/// </summary>
public enum SearchIndex
{
All,
Apparel,
Appliances,
ArtsAndCrafts,
Automotive,
Baby,
Beauty,
Blended,
Books,
Classical,
Collectibles,
DigitalMusic,
Grocery,
DVD,
Electronics,
HealthPersonalCare,
HomeGarden,
Industrial,
Jewelry,
KindleStore,
Kitchen,
LawnGarden,
Magazines,
Marketplace,
Merchants,
Miscellaneous,
MobileApps,
MP3Downloads,
Music,
MusicalInstruments,
MusicTracks,
OfficeProducts,
OutdoorLiving,
PCHardware,
PetSupplies,
Photo,
Shoes,
Software,
SportingGoods,
Tools,
Toys,
UnboxVideo,
VHS,
Video,
VideoGames,
Watches,
Wireless,
WirelessAccessories,
}

July 17th, 2013

Clockwork (stock photo by xtrapink)

This picks up with the code generation series. This is planned to be the last post in this mini series. See past posts:

This post will go over some basics using the CodeDom. The code samples used in this post come from a project I wrote that allowed me to copy/paste parts of a customer spec and generate classes that could be used for serialization.

CodeDom is flexible enough for a wide spectrum of code generation needs. As with all things, the power that comes with that generating code with CodeDom is balanced by the complexity of using CodeDom.

Let’s dive right into some code:

// Generate the container unit
CodeCompileUnit program = new CodeCompileUnit();

// Generate the namespace
CodeNamespace ns = new CodeNamespace("Net.Sirchristian");

// Add the required imports
ns.Imports.Add(new CodeNamespaceImport("System"));
ns.Imports.Add(new CodeNamespaceImport("System.Xml.Serialization"));

CodeDom works off of CodeCompileUnits. A CodeCompileUnit can be thought of as a file to be generated. Every file to be generated will construct a CodeCompileUnit. CodeNamespace is equivalent to a namespace block in C#.

// REPRESENTATIVE GENERATED FILE
namespace Net.Sirchristian { }

To the namespace we add CodeNamespaceImport which are the ‘using’ statements.

// REPRESENTATIVE GENERATED FILE
namespace Net.Sirchristian 
{ 
    using System;
    using System.Xml.Serialization;
}

So far fairly straight forward. Pretty much a one -> one CodeDom object to code structure. One thing to note is we have not yet added anything to our CodeCompileUnit. We have to fully construct the objects that will go inside the CodeCompileUnit then we can add namespace to it. This is true with any container object when using CodeDom. The children must be fully populated before getting put into the container. Next we will generate our class container.

// Declare the class
CodeTypeDeclaration recordClass = new CodeTypeDeclaration()
{
    Name = "Record", 
    IsClass = true
};

A class is represented by a CodeTypeDeclaration. A CodeTypeDeclaration can be any user definable types allowed by the CLR, currently that means class, interface, enum, struct, or delegate (although to generate a delegate you have to use CodeTypeDelegate which inherits from CodeTypeDeclaration). Now we have to generate objects to add to the class.

string anyString = "property of chris";

// Make a nice property name by making it title case, and no spaces
string propertyName = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(anyString.ToLower());
propertyName = Regex.Replace(propertyName, @"\W|\s", "");

// Make the private file starting with 2 underscores and an all lower name
string privateFieldName = "__" + propertyName.ToLower();

// Generate the private field
CodeMemberField field = new CodeMemberField()
{
	Name = privateFieldName,
	Type = new CodeTypeReference(typeof(string)),
	Attributes = MemberAttributes.Private
};

// Generate the property
CodeMemberProperty property = new CodeMemberProperty()
{
	Name = propertyName,
	Type = new CodeTypeReference(typeof(string)),
	Attributes = MemberAttributes.Public | MemberAttributes.Final,
	HasGet = true,
	HasSet = true
};

// Add the return field statement to the property
property.GetStatements.Add(new CodeMethodReturnStatement(
	new CodeFieldReferenceExpression(
		new CodeThisReferenceExpression(), privateFieldName)));

// Add the set field to value to the property
property.SetStatements.Add(
	new CodeAssignStatement(
		new CodeFieldReferenceExpression(
			new CodeThisReferenceExpression(), privateFieldName),
		new CodePropertySetValueReferenceExpression()));

// Add a comment
string comment = "Remember children: ALWAYS COMMENT YOUR CODE.";
property.Comments.Add(new CodeCommentStatement(comment, true));

// Add the XmlElement Attribute
CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(
	new CodeTypeReference(typeof(XmlElementAttribute)),
		new CodeAttributeArgument("Type", new CodeTypeOfExpression(typeof(string))),
		new CodeAttributeArgument("ElementName", new CodePrimitiveExpression(propertyName)),
		new CodeAttributeArgument("Namespace", new CodePrimitiveExpression("http://xml.sirchristian.net")))
property.CustomAttributes.Add(attribute);

What the above code does is add a public property with a getter and setter that will get and set the private field. The public property is decorated with an XmlElement attribute. This is where you can start to notice some of the power/flexibility trade offs of using CodeDom. Conceptually we will be building out something that looks like.

// REPRESENTATIVE GENERATED FILE
// Remember children: ALWAYS COMMENT YOUR CODE.
[XmlElementAttribute(
	Type=typeof(string), 
	ElementName="PropertyOfChris", 
	Namespace="http://xml.sirchristian.net")]
public string PropertyOfChris
{
    get
    {
        return this.__propertyofchris;
    }
    set
    {
        this.__propertyofchris = value;
    }
}
private string __propertyofchris;

To generate that we use the following objects from CodeDom:

I won’t go over all the objects in details, but I want to illustrate that everything that needs to be generated will have an object associated with it. To see more of the CodeDom objects look at the CodeDom namespace on MDSN.

There are patterns on how the CodeDom object model is structured. Mostly this can be inferred by the object name. There are CodeObjects , CodeExpressions, CodeStatements, all of which need to be combined just like you would need to type out tokens when editing a source file. The big benefit to CodeDom is that once the structures are built out with CodeDom objects it is easy to add additional logic around them. This is the flexibility of CodeDom.

So we’ve pretty much constructed all the objects we need to have the code generated for us, the last step is to add the constructed CodeDom objects to the appropriate parent objects.

// add property to the class
recordClass.Members.Add(property);

// add the field to the cass
recordClass.Members.Add(field);

// Add record class to the namespace
ns.Types.Add(recordClass);

program.Namespaces.Add(ns);

We finally added the members to the class, the class to the namespace, and the namespace to the CodeCompileUnit. We have a whole source file finally constructed. The last step is to render the CodeCompileUnit into a C# source file. We do that by created a CodeProvider. Specifically a CSharpCodeProvider (although as long as the CodeDom objects don’t contain any C# specific features all the C# code used above could generate a VB file just by changing CSharpCodeProvider to a VBCodeProvider).

using (var outFile = File.Open("out.cs", FileMode.Create))
using (var fileWriter = new StreamWriter(outFile))
using (var indentedTextWriter = new IndentedTextWriter(fileWriter, "    "))
{
	// Generate source code using the code provider.
	var provider = new Microsoft.CSharp.CSharpCodeProvider();
	provider.GenerateCodeFromCompileUnit(program, 
		indentedTextWriter, 
		new CodeGeneratorOptions() { BracingStyle = "C" });
}

One more cool thing…creating an assembly at runtime!

Another cool thing about CodeDom is that an Assembly can actually be compiled and used at runtime.

// Build the parameters for compilation
CompilerParameters cp = new CompilerParameters();

// Add references
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);

// Save the assembly in memory
cp.GenerateInMemory = true;

// Invoke compilation.
CompilerResults cr = provider.CompileAssemblyFromDom(cp, program);

if (cr.Errors.Count > 0)
{
    // Build an exception
    ApplicationException exception = new ApplicationException("Error building assembly");
    StringBuilder errorBuilder = new StringBuilder();
    foreach (CompilerError ce in cr.Errors)
    {
        exception.Data.Add(ce.ToString(), ce);
    }

    throw exception;
}

Assembly assembly = cr.CompiledAssembly;

CompilerParameters and CompilerResults are also part of the CodeDom namespace. Feed the CodeProvider with the CompilerParameters and the CodeCompileUnit and the provider can compile the generated code for you, without even needed to generate code!

This is the last entry I planned for the code generation series. Want more, or have questions, leave a comment, or ping me on twitter @sirchristian.

June 19th, 2013

stock.xchng - Student Handbook 001 (stock photo by SP_AL_UK)Over the years I’ve collected some rules I keep in my head when I am coding. Some I’ve come up with on my own, others I’ve stolen from @jonwagnerdotcom and @jbright, books have provided some, and other I completely forgot where I’ve picked them up. Feel free to use them in your own head while you code.

  1. THINK

    Above all else think about what you are doing. Don’t blindly follow patterns. Make sure what you are doing makes sense. Trust your own brain.

  2. Code different things differently, same things the same.
    Don’t force a DRY pattern on something that is really different, but if the pattern is really the same use the same code for it.
  3. Better is the enemy of done.
    Code as best you can, but don’t be afraid to ship it. Code is a tool to be used. Nobody can use your code if you don’t let them.
  4. Unwritten code has no bugs.
    Don’t write code unless you have to. Nobody is perfect; your code will have unforeseen effects. Determine before hand if the problem really needs code to be solved.
  5. Do not repeat yourself (DRY).
    Make sure your code is neat and separated so it can be reused. Don’t type (or copy/paste) the same code twice. Actually any time you copy/paste code it better be for a good reason.
  6. Don’t be afraid to delete code, it’s in source control.
    (It is in source control right? Seriously it better to use bad source control over no source control). Undeleted code just clogs up the code base. Delete code that isn’t needed and lean on source control for history. Too may times have I see old code hang around because nobody was sure why it was needed in the first place.
  7. It’s just bits and bytes.
    Don’t be afraid to refactor. The raw materials for code are cheap.
  8. Take pride in your work. Don’t be sloppy.
    Coding is a craft. Pay attention to the code you wrote and take some pride in it.
  9. Bugs happen.
    Nobody can plan for the future completely. Bugs will happen and that’s OK. Fix them when they arise.
  10. Have fun.
    Not every task will be fun, but strive to find fun in what you are coding. It will keep you sane and create a better product.