Click here to Skip to main content
13,002,169 members (82,984 online)
Click here to Skip to main content
Add your own
alternative version


81 bookmarked
Posted 21 Sep 2007

CodeDom Assistant

, 21 Sep 2007
Rate this:
Please Sign up or sign in to vote.
Generating CodeDom Code By Parsing C# or VB
Screenshot - codedomassistant.gif


I find writing CodeDom code kind of like writing assembly. It's like cutting the grass with a pair of scissors or unloading a truck load of sand with a spoon. Its long winded, it can be done, but it is tedious. However, there are advantages in using CodeDom.

Now, it would be nice if you could whip up a class in VB or C# and generate the CodeDom code. CodeDom Assistant does this with the help of SharpDevelop's NRefactory Library in conjunction with writing our own CodeDomProvider to generate C# CodeDom code. The code you get will construct a CodeDom compileunit, and it will definitely be ugly. But what can you expect from a machine?


Code Generation can be done using various techniques. In essence, code generation saves time, and enables you to create code using established patterns.

In the world of .NET, one technique is to use CodeDom. It allows you create a document object model of the code. This can by either compiled into an assembly or used to generate code. Every .NET language should have an implementation of a CodeDomProvider to generate code. The problem is that CodeDom does not implement every syntax construct of every language. In essence, it is a subset, but there are enough operations to emulate most language constructs.

Parsing C# or VB is going to be the toughest part, but luckily one of SharpDevelop's little libraries is NRefactory. This has the machinerary required to parse C# or VB code. The key component for us is the CodeDomVisitor class. Sadly, it is only a partial implementation. They implement enough to run SharpDevelop's form generation. I am not saying I have completed the implementation, rather, I have filled most of the holes in the CodeDomVisitor.

The second part is implementing a CodeDomCodeProvider. This will take a CodeDom compile unit and generate C# code that will create a CodeDom compile unit.

Alternatives To Unsupported CodeDom Constructs

When converting C# to CodeDom, certain constructs will not be able to be mapped directly into a CodeDom element. Rather we have to emulate the intent of the code. I am sure better transformations can be made, but these are sufficient for my needs. For example: int a = b++; is definitely not the same as the transformed CodeDom int a = (b = (b + 1));.

Not all constructs are going to be able to be transformed perfectly into CodeDom; they are merely sufficient for my needs. When I originally wrote the code in C# I did so with these limitations in mind. For example:

The foreach statement is handled using the for iterator and GetEnumerator(). Behold:

foreach (string s in mylist)

Can be constructed in CodeDom as:

for (System.Collections.IEnumerator _it1 = mylist.GetEnumerator(); 
    _it1.MoveNext(); )
    string s = ((string)_it1.Current);

The do statement is handled using the for iterator. For example:

while (expr);

Can be constructed in CodeDom as:

for (bool _do1 = true; _do; _do = expr)

The while statement is handled again with the for iterator. For example:

while (expr)

Can be constructed in CodeDom as

for (; expr; )

The continue and break statements are handled using the goto statements. For example:

for (int i = 0; i < 5; i++)
    if (i < 2)

    if (i == 3)

Can be constructed in CodeDom as:

for (int i = 0; i < 5; i = i + 1)
    if (i < 2)
        goto continue1;

    if (i == 3)
        goto break1;


Unary operators: i++; ++i; i--; --i; !; can be constructed using the binary operators: i = i + 1; etc..

The switch statement becomes a nested if statement.

case label1:

case label2:


Can be constructed in CodeDom as:

object _switch1 = expr;

if (_switch1.Equals(label1))
    if (_switch1.Equals(label2))

The using(new a()) {} statement can be emulated with:

object _dispose1 = null;
    _dispose1 = new a();
    if (((_dispose1 != null) 
       && (typeof(System.IDisposable).IsInstanceOfType(_dispose1) == true)))

Constructing CodeDom Using NRefactory

The generate function uses NRefactory parser. NRefactory supports C# and VB. I tend to use C#, and have not tested the VB. The OutputClass is essentially the output combobox selection. There are native C# and VB NRefactory output transformations, which are much more complete than CodeDom. For other languages we use the CodeDomVisitor which maps the NRefactory parser output to CodeDom. The CodeDom CodeCompileUnit is then passed to a CodeDomProvider which generates output.

void Generate(ICSharpCode.NRefactory.SupportedLanguage language, 
    TextReader inputstream, OutputClass output)
    ICSharpCode.NRefactory.IParser parser = ParserFactory.CreateParser(
        language, inputstream);

    if (parser.Errors.Count > 0)
        ICSharpCode.Core.ExceptionDialog dlg = 
             new ICSharpCode.Core.ExceptionDialog(
             null, "Error Parsing Input Code");

    if (output.CodeDomProvider != null)
        CodeDomVisitor visit = new CodeDomVisitor();

        visit.VisitCompilationUnit(parser.CompilationUnit, null);

        // Remove Unsed Namespaces
        for (int i = visit.codeCompileUnit.Namespaces.Count - 1; i >= 0; i--)
            if (visit.codeCompileUnit.Namespaces[i].Types.Count == 0)

        CodeGeneratorOptions codegenopt = new CodeGeneratorOptions();
        codegenopt.BlankLinesBetweenMembers = true;

        System.IO.StringWriter sw = new System.IO.StringWriter();

            visit.codeCompileUnit, sw, codegenopt);

        this.scintillaOutput.Text = sw.ToString();

        AbstractAstTransformer transformer = output.CreateTransformer();

        // do what SharpDevelop does...
        List<ISpecial> specials = 
        if (language == SupportedLanguage.CSharp && 
            transformer is ToVBNetConvertVisitor)
        else if (language == SupportedLanguage.VBNet && 
            transformer is ToCSharpConvertVisitor)

        parser.CompilationUnit.AcceptVisitor(transformer, null);

        IOutputAstVisitor prettyprinter = output.CreatePrettyPrinter();

        using (SpecialNodesInserter.Install(specials, prettyprinter))
            prettyprinter.VisitCompilationUnit(parser.CompilationUnit, null);

        this.scintillaOutput.Text = prettyprinter.Text;

The NRefactory CodeDomVisitor class needed to be updated to implement more C# constructs. I am sure I have have missed a few.

Generating C# Code CodeDom

All CodeDom compile units can be passed to any CodeDomProvider to generate code. So, we write a new CodeDom provider that will generate CodeDom code for us. The implementation is quite simple. The main job of the CodeDomCodeProvider is to create an ICodeGenerator.

public class CodeDomCodeProvider : System.CodeDom.Compiler.CodeDomProvider
    public CodeDomCodeProvider()
            : base()

    public override string FileExtension
            return "cs";

    public override System.CodeDom.Compiler.ICodeGenerator CreateGenerator()
        return new CodeGenerator();

    public override System.CodeDom.Compiler.ICodeCompiler CreateCompiler()
        return null;

The CodeGenerator then traverses the CodeDom elements and outputs code that will reconstruct the tree when compiled.

Using Other CodeDomProviders

On initialisation CodeDom Assistant scans the GAC to find assemblies that have an implementation of CodeDomProvider. Since the output of the parsed C#/VB is CodeDom the output can be generated by any CodeDomProvider. So it could act as an effective language Convertor.

Points of Interest

You can only convert code that compiles. It is not very good at telling why it did not compile. The other issue I have found is that it may parse the file, but the CodeDom it produces is incomplete. This may cause the CodeDomProvider CodeGenerator to barf. Usually with some obscure error, like e value is null.

The output of CodeDomCodeProvider is ugly, but assists you in the construction of creating code generators with CodeDom. A lot of our code generation is done through the meta-data of a database. So this code would only be a starting point.


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Web Developer
Australia Australia
No Biography provided

You may also be interested in...

Comments and Discussions

GeneralMy vote of 5 Pin
deepak_rai7-Mar-13 18:12
memberdeepak_rai7-Mar-13 18:12 
GeneralWell done Pin
Espen Harlinn21-Feb-13 7:35
mvpEspen Harlinn21-Feb-13 7:35 
GeneralMy vote of 5 Pin
chprogmer14-Apr-11 5:07
memberchprogmer14-Apr-11 5:07 
GeneralMy vote of 5 Pin
Tendoors27-Nov-10 8:47
memberTendoors27-Nov-10 8:47 
Generalgreat tool Pin
some_beginner3-Sep-10 3:13
membersome_beginner3-Sep-10 3:13 
GeneralUse in proof of concept tool Pin
finlay66621-Mar-10 10:17
memberfinlay66621-Mar-10 10:17 
GeneralDoesn't seem to generate CodeDom code Pin
dosaduik10-Sep-09 13:58
memberdosaduik10-Sep-09 13:58 
GeneralA must have if you need to write CodeDom Pin
GrimaceOfDespair26-Feb-09 3:23
memberGrimaceOfDespair26-Feb-09 3:23 
GeneralFantastic Tool Pin
Akleinek25-Sep-08 3:54
memberAkleinek25-Sep-08 3:54 
Generallogic bug in GenerateCodeTypeReference building string for array Pin
drdandle15-Aug-08 7:20
memberdrdandle15-Aug-08 7:20 
QuestionNot outputting events Pin
drdandle11-Aug-08 4:38
memberdrdandle11-Aug-08 4:38 
GeneralUse your code:SampleCode.cs to test,Error Pin
guaike15-Jun-08 16:28
memberguaike15-Jun-08 16:28 
GeneralVistax64 Pin
Member 456280616-Apr-08 0:51
memberMember 456280616-Apr-08 0:51 
GeneralRe: Vistax64 Pin
chprogmer14-Apr-11 5:03
memberchprogmer14-Apr-11 5:03 
Generallanguage convertor Pin
sardarkhan27-Mar-08 20:39
membersardarkhan27-Mar-08 20:39 
GeneralI looked everywhere for this!!! Pin
jbosltad8-Jan-08 10:36
memberjbosltad8-Jan-08 10:36 
Generalthis is amazing Pin
dave.dolan28-Nov-07 10:21
memberdave.dolan28-Nov-07 10:21 
GeneralGreat Stuff Pin
sefstrat6-Nov-07 11:35
membersefstrat6-Nov-07 11:35 
GeneralNice articlel, but ... Pin
Adar Wesley1-Oct-07 9:35
memberAdar Wesley1-Oct-07 9:35 
GeneralRe: Nice articlel, but ... Pin
dave.dolan28-Nov-07 10:31
memberdave.dolan28-Nov-07 10:31 
GeneralI know I'm doing something wrong.... Pin
ednrgc24-Sep-07 6:28
memberednrgc24-Sep-07 6:28 
I know I'm doing something wrong, but I'm getting an error whenever I try to test any codedom code. Any help is greatly appreciated.

Error Description:

Could not load file or assembly 'file:///C:\CodeDom Assistant\CodeDomAssistant_Demo\script_44d3a227-aaf1-431b-a788-c14c939c8037.dll' or one of its dependencies. The system cannot find the file specified.
at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
at System.Reflection.Assembly.InternalLoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, Boolean forIntrospection, StackCrawlMark& stackMark)
at System.Reflection.Assembly.LoadFrom(String assemblyFile, Evidence securityEvidence)
at System.Activator.CreateInstanceFrom(String assemblyFile, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, Evidence securityInfo)
at RemoteLoader.RemoteLoaderFactory.Create(String assemblyFile, String typeName, Object[] constructArgs) in c:\zips\C# Source\CodeDom Assistant\sln.CodeDomAssistant\RemoteLoader\RemoteLoaderFactory.cs:line 24
at RemoteLoader.RemoteLoaderFactory.Create(String assemblyFile, String typeName, Object[] constructArgs)
at CodeDomAssistant.CSharpSnippet.Execute(String method, Object[] args) in c:\zips\C# Source\CodeDom Assistant\sln.CodeDomAssistant\CodeDomAssistant\CSharpSnippet.cs:line 106
at CodeDomAssistant.FormCodeAssistant.CompileTestCodeDom
GeneralRe: I know I'm doing something wrong.... Pin
raygilbert24-Sep-07 12:52
memberraygilbert24-Sep-07 12:52 
GeneralRe: I know I'm doing something wrong.... Pin
ednrgc25-Sep-07 1:45
memberednrgc25-Sep-07 1:45 
GeneralExcellent Pin
mcory224-Sep-07 5:55
membermcory224-Sep-07 5:55 
GeneralRe: Excellent Pin
raygilbert24-Sep-07 13:16
memberraygilbert24-Sep-07 13:16 
GeneralNice article Pin
Daniel Grunwald22-Sep-07 9:04
memberDaniel Grunwald22-Sep-07 9:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170624.1 | Last Updated 21 Sep 2007
Article Copyright 2007 by raygilbert
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid