CodeDom – generate code dynamically

CodeDom is a feature which allows you to create code dynamically.
It means, you can define an object (System.CodeDom.CodeCompileUnit) which describes a new type to be created. Then you can print out prepared schema to file with c# code.
This sample shows how to prepare CodeCompileUnit for new class ‘Person’ and how to write code file with this class.

    class Program
    {
        static void Main(string[] args)
        {
            var template = CreateCodeTemplate("Person", 
                                        new Tuple<Type, string>(typeof(int), "Age"), 
                                        new Tuple<Type, string>(typeof(string), "Name"));
            var generatedFileName = GenerateCode(template);
            Console.WriteLine(generatedFileName);
            Console.ReadLine();
        }

        /// <summary>
        /// Creates schema of the code you want to generate. 
        /// Schema will contain class with given name and properties.
        /// </summary>
        /// <returns></returns>
        public static CodeCompileUnit CreateCodeTemplate(string className, params Tuple<Type, string>[] properties)
        {
            var mySample = new CodeCompileUnit();

            var myNamespace = new CodeNamespace("ExternalTool.Base");
            myNamespace.Imports.Add(new CodeNamespaceImport("System.Linq"));

            var myClass = new CodeTypeDeclaration(className);
            myClass.IsClass = true;
            myClass.Comments.Add(new CodeCommentStatement("Use this autogenerated class to create specific items."));

            foreach (var p in properties)
            {
                var privateMember = new CodeMemberField(typeof(int), "_" + p.Item2);

                var prop = new CodeMemberProperty();
                prop.Name = p.Item2;
                prop.Type = new CodeTypeReference(typeof(int));
                prop.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), privateMember.Name)));
                prop.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), privateMember.Name), new CodePropertySetValueReferenceExpression()));

                myClass.Members.Add(privateMember);
                myClass.Members.Add(prop);
            }

            mySample.Namespaces.Add(myNamespace);
            myNamespace.Types.Add(myClass);

            return mySample;
        }

        /// <summary>
        /// Creates file with the C# code. Path to the created file is returned.
        /// </summary>
        /// <param name="template"></param>
        /// <returns></returns>
        public static string GenerateCode(CodeCompileUnit template)
        {
            var codeProvider = new CSharpCodeProvider();
            var fileName = Path.GetTempFileName();
            using (var writer = new StreamWriter(fileName, false))
            {
                var itWriter = new IndentedTextWriter(writer, "  ");// writes text with given tabbing
                codeProvider.GenerateCodeFromCompileUnit(template, itWriter, new CodeGeneratorOptions());
            }

            return fileName;
        }
    }

When the code above is started, file like this is generated:

//------------------------------------------------------------------------------
// <auto-generated>
//     Ten kod został wygenerowany przez narzędzie.
//     Wersja wykonawcza:4.0.30319.42000
//
//     Zmiany w tym pliku mogą spowodować nieprawidłowe zachowanie i zostaną utracone, jeśli
//     kod zostanie ponownie wygenerowany.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ExternalTool.Base
{
    using System.Linq;


    // Use this autogenerated class to create specific items.
    public class Person
    {

        private int _Age;

        private int _Name;

        private int Age
        {
            get
            {
                return this._Age;
            }
            set
            {
                this._Age = value;
            }
        }

        private int Name
        {
            get
            {
                return this._Name;
            }
            set
            {
                this._Name = value;
            }
        }
    }
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s