Sunday, October 17, 2010

Code generation with partial & Attribute

The last couple of weeks I have built a Visual Studio Addin that can help up with trivial editor features and not so trivial features like code generation.

One of the things that I am going to try the next couple of weeks is to generate a default implementation class from an interface.

2 ways to structure basic code generation in C# are:
  • the C# form approach where a class is split into 2 files (1 generated and 1 editable) with the partial keyword, and
  • the "double-derived" pattern with a base and implementation file (1 generated and 1 editable)
The first mentioned approach doesn't support that you can choose what should be generated and what shouldn't; you just have to live with the split made by the generator.
The second approach adds an extra inheritance link and you avoid calling the generated code by overriding methods/properties and not calling it via base; generated code becomes dead code.

Here is a 3rd approach... and I have yet to see if it works in practice.

Generate a partial class with 2 files
First we generate "Class1.cs", the editable file, and "Class1.generated.cs", the generated file.

They could look as follows:
Now the developer wants to customize the Bar property...

Support developer customization
The developer cut-paste the Bar code to the editable file, removes the Generated attribute and performs her customizations:
What happens now when the code generator is called again to create Class1?

Re-generate the partial class generated file
The generator uses reflection on the compiled assembly and only generates missing properties/methods and re-generates the properties/methods with the Generated attribute....

This means that the developer's changes are kept intact and she actively decides on the features being generated.

Maybe it can be done that simple... the catch is that the generator only can respect successfully compiled developer changes... but that might be OK e.g. Test Driven .Net requires a successful build to run tests.