Monday, February 9, 2009

Extending code generation with partial classes and inheritance

One of the bigger problems with Code Generation is changeability. Generated code should never be modified. Anything that you modify on a generated class will be lost when you run the generation again. The problem is that if you need to extend/alter your generated class, you cannot do it without taking it out of the generation process (which is sometimes acceptable, but mostly not).

Gladly, C# 2.0 introduced the concept of “partial” classes a long time ago. You must have seen it. When you create a new Windows Form, you get two classes; one is for the generated code in InitializeComponents and the other is for you to use. If your architecture is similar to this case, you can do the same: generate a partial class with all the generated code and have a partial class with any extra code the developer may need to add.

Most of the times, though, the need is to replace the generated code with something completely different in some specific cases. That is, almost all the generated code is ok, but one or two methods in one or two classes need to be replaced. In this case, you can use a different approach: the “double-derived” pattern introduced in Microsoft DSL. It works like this:

When you generate code, you generate 2 classes instead of one. The first class (MyGeneratedClassBase) will have all the methods implemented and marked as virtual. The second class (MyGeneratedClass) will inherit from the first class, and will be marked as partial. This will be transparent to whoever needs to use the class and it will allow you to change the implementation of the methods you need via overriding. If you regenerate the classes afterwards, nothing breaks.

Let me show you in an example. Say you are generating classes from a database. You generate each table with properties for the fields and CRUD methods. Something like this:

public class Customer
{

public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }

public int Create()
{
//some implementation
}

public void Update()
{
//some implementation
}

public void Delete()
{
//some implementation
}

public void Retrieve()
{
//some implementation
}

}


Now, let’s suppose you need to override the Delete method so you will not be allowed to delete customers (let’s assume this makes sense just for the sample). If you change the generated class directly, you’ll loose your changes when the class is regenerated. In the double-derived pattern, you’ll have this instead:



public class CustomerBase
{

public virtual int Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }

public virtual int Create()
{
//some implementation
}

public virtual void Update()
{
//some implementation
}

public virtual void Delete()
{
//some implementation
}

public virtual void Retrieve()
{
//some implementation
}

}

public partial class Customer : CustomerBase
{
}


A developer will use the Customer class as before, but now you can create a new partial class for Customer, overriding the Delete method like this:



public partial class Customer
{
public override void Delete()
{
}
}


Notice that this class is not the same as the generated class, but a new partial class created by you. Also notice that you cannot change the return value for the method. You can change the parameters of the method by creating a new overload for it.



This way you’ll be able to change standard implementation on a need-to-change basis while still using your code generation for most of your code. Also, you can regenerate on every build if needed.

Registry-based configuration

When you need to design your system’s configuration options, one of the available options is to use the Windows Registry. The Registry has several advantages and disadvantages over an xml-based .config file. Let’s go through them:

  • Pros
    • Windows Standard
    • Strongly-typed data
    • User Configuration
    • Atomicity
    • Remote Administration
  • Cons
    • Difficult to manipulate / Bad tools
    • Difficult to backup
    • May leave unused data behind
    • Can’t easily move settings to a different computer

All of this makes registry-based configuration a good choice for two types of configuration: advanced settings (of the type that no normal user should be touching, but an advanced user may need to change) and user settings (such as last position of a window on the screen, last search parameters, etc).

The focus is to do this:

configuration.WindowsPosition.Top = top;
configuration.WindowsPosition.Left = left;


instead of this:



windowPositionKey = Registry.CurrentUser.OpenSubKey(@"Software\MyCompany\MyProgram\1.0\WindowsPosition", true);
windowPositionKey.SetValue("Top", top);
windowPositionKey.SetValue("Left", left);


When using the registry for configuration, it makes code more explicit and simpler, which is always a plus.



So, how does this work? First, the generated class will look like this:



public class WindowPositionKey
{
private Microsoft.Win32.RegistryKey registry;

public override string KeyName
{
get
{
return @"WindowPosition";
}
}

public WindowPositionKey()
{
registry = Registry.LocalMachine.OpenSubKey@"Software\MyCompany\MySoftware\1.0\Configuration\WindowPosition", true);
}

public int Top
{
get
{
return (int) registry.GetValue(@"Top");
}
set
{
registry.SetValue(@"Top", value);
}
}

public int Left
{
get
{
return (int) registry.GetValue(@"Left");
}
set
{
registry.SetValue(@"Left", value);
}
}
}


It looks pretty simple, and it can even be made manually. And that is generally true for any code generation task. The point here is quantity. When you have several configuration values in different keys, it makes sense to have a tool generate all that code for you. Also, you can do some fancy stuff. For instance, the key named “Configuration” may have several subkeys (let’s say, WindowPosition and ConnectionProxy for this sample). That code will look like this:



public class RootRegistryKey : RegistryGen.RegistryKey
{
private Microsoft.Win32.RegistryKey registry;

public override string KeyName
{
get
{
return @"Configuration";
}
}

public RootRegistryKey()
{
registry = Registry.LocalMachine.OpenSubKey(@"Software\MyCompany\MySoftware\1.0\Configuration", true);
}

public WindowPositionKey WindowPosition
{
get
{
return new WindowPosition(registry);
}
}

public ConnectionProxyKey ConnectionProxy
{
get
{
return new ConnectionProxyKey(registry);
}
}

public override IList<RegistryGen.RegistryKey> GetSubKeys()
{
IList<RegistryGen.RegistryKey> keys = new List<RegistryGen.RegistryKey>();

keys.Add(WindowPosition);
keys.Add(ConnectionProxy);
return keys;
}
}


There are a few changes in WindowPositionKey that must be implemented for this to work. First, we need a constructor with a Microsoft.Win32.RegistryKey parameter. Also, it should inherit from RegistryGen.RegistryKey for the GetSubKeys() method. As you add levels of complexity, manually coding the classes gets more complex.



The code generation task, though, is almost exactly the same. We have a GenerateClass() method that receives all the necessary information to generate a single registry class (className, fullName, etc). For the first change, you only need to change this:



public class <#= CleanName(className) #>Key


to this:



public class <#= CleanName(className) #>Key : <#= Namespace #>.RegistryKey


The second change is as easy. Just change this:



public <#= CleanName(className) #>Key()
{
registry = Registry.<#= GetRootString(registryParts) #>.OpenSubKey(@"<#= fullName #>", true);
}


to this:



internal <#= CleanName(className) #>Key(Microsoft.Win32.RegistryKey registry)
{
this.registry = registry.OpenSubKey(@"<#= lastPart #>", true);
}


and you’re all set!



If you’re interested, you can review the RegistryGen sample in Visual T4 Code Generator alpha for the full sample.

Sunday, February 8, 2009

Creating valid C# identifiers

In code generation, it’s very common to need to create a valid identifier. For instance, you may need to create a class name, field, property, method, etc based on the name of a table, a file name, a registry key. The problem with this type of generation is that the rules that make one valid may not apply to the other. For instance, “1st File.txt” is a perfectly valid file name, but it’s not a valid C# identifiers.

Valid identifiers in C# are defined in the C# Language Specification, item 2.4.2. The rules are very simple:

- An identifier must start with a letter or an underscore
- After the first character, it may contain numbers, letters, connectors, etc
- If the identifier is a keyword, it must be prepended with “@”

Applying these rules is pretty straightforward. The following code validates items 1 and 2:

private string CleanName(string name)

{ //Compliant with item 2.4.2 of the C# specification
System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(@"[^\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Nl}\p{Mn}\p{Mc}\p{Cf}\p{Pc}\p{Lm}]");
string ret = regex.Replace(name, "_"); //The identifier must start with a character if (!char.IsLetter(ret, 0))

ret = string.Concat("_", ret);
return ret;
}


To validate item 3, you can use the C# provider as follows:

ret = Microsoft.CSharp.CSharpCodeProvider.CreateProvider("C#").CreateEscapedIdentifier(ret); 


This code will generate an underscore for each space in the identifier. For instance, “c:\1st file.txt” will be generated as “c__1st_file_txt”. If you want to prevent that, change the regex.Replace(name, “_”) with regex.Replace(name, “”). You may also consider capitalizing the first letter after each “_” and then eliminating the “_”.


Finally, you may prefer to have the “keyword” identifiers named with a prefix different from “@”. If that’s the case, use IsValidIdentifier in the CodeDomProvider to know which identifiers are keywords. A full corrected code snippet is below:

private static string CleanName(string name)
{
//Compliant with item 2.4.2 of the C# specification

System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(@"[^\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Nl}\p{Mn}\p{Mc}\p{Cf}\p{Pc}\p{Lm}]");
string ret = regex.Replace(name, "");
//The identifier must start with a character or a "_"
if (!char.IsLetter(ret, 0) !Microsoft.CSharp.CSharpCodeProvider.CreateProvider("C#").IsValidIdentifier(ret))

ret = string.Concat("_", ret);
return ret;
}

The only problem you may find after this is with duplicated identifiers. “c:x” will generate the same identifier as “c.x”, which may be a problem depending on your particular code generation needs. If you run into this, use a list to store already used identifiers. When you find that an identifier has been used, add a number at the end and check again.

Wednesday, February 4, 2009

Customizing generated code in ASP.NET MVC

Just in case you missed the news, the ASP.NET MVC team is using T4 to generate code (yeah!)
The way they have integrated T4 in their own product is not what we would have expected (they wrote their own T4 host) so we took our Visual T4 Editor and Visual T4 Code Generator bits and added them knowledge about this custom host in order to offer the best possible tooling experience.

You can now see properties of their templates appearing in the Properties window, easily set them and preview how the generation will look like with a single click.

Adrian has recorded a quick video of how this is looking like already, watch it here.

We added this support last week so it is not there yet on the public bits, but I promess it will be there soon!

Tuesday, February 3, 2009

New Blog About Code Generation With T4 in Visual Studio!

While developing the Visual T4 Code Generator edition my team and I are constantly having discussions on how the best code generation tool in earth should look like and also about more “abstract” code generation chores not necessarily related to the product we’re developing.

So it occurred to me (yes, I’m that clever…) that we should take our internal document drafts from our internal wiki and put all this stuff into a blog (of course we will remove the bad language first) to make our plans more public and gather community feedback while we’re at it.

In this new blog you will find posts by Adrian, Joaquin, Jose and me (and if I get lucky I may get other Clarius people to blog too)

Please subscribe and let us know what do you think, thanks!