CodeDom – Dynamic Code Generation: Rectangle Class

/*
 * https://yinyangit.wordpress.com
 * 13 January 2011
 */

using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using System.Text;
using Microsoft.CSharp;
using Microsoft.VisualBasic;

namespace ConsoleApplication1
{
    class Program
    {
        public CodeCompileUnit CreateRectangleCode()
        {
            CodeNamespace cNamespace = new CodeNamespace("CodeDomExample");

            cNamespace.Imports.Add(new CodeNamespaceImport("System"));

            CodeTypeDeclaration cClass = new CodeTypeDeclaration("Rectangle");
            cNamespace.Types.Add(cClass);

            // fields
            CodeMemberField field1 = new CodeMemberField("Int32", "_length");
            field1.Attributes = MemberAttributes.Private;
            CodeMemberField field2 = new CodeMemberField("Int32", "_width");
            field2.Attributes = MemberAttributes.Private;

            cClass.Members.Add(field1);
            cClass.Members.Add(field2);

            // properties
            CodeMemberProperty property1 = new CodeMemberProperty();
            property1.Name = "Length";
            property1.Attributes = MemberAttributes.Public;
            property1.Type = new CodeTypeReference("Int32");
            property1.HasGet = true;
            property1.HasSet = true;

            property1.GetStatements.Add(new CodeMethodReturnStatement(
                new CodeFieldReferenceExpression(
                    new CodeThisReferenceExpression(), "_length")));
            property1.SetStatements.Add(new CodeAssignStatement(
                new CodeFieldReferenceExpression(
                    new CodeThisReferenceExpression(), "_length"),
                    new CodeArgumentReferenceExpression("value")));

            CodeMemberProperty property2 = new CodeMemberProperty();
            property2.Name = "Width";
            property2.Attributes = MemberAttributes.Public;
            property2.Type = new CodeTypeReference("Int32");
            property2.HasGet = true;
            property2.HasSet = true;

            property2.GetStatements.Add(new CodeMethodReturnStatement(
                new CodeFieldReferenceExpression(
                    new CodeThisReferenceExpression(), "_width")));
            property2.SetStatements.Add(new CodeAssignStatement(
                new CodeFieldReferenceExpression(
                    new CodeThisReferenceExpression(), "_width"),
                    new CodeArgumentReferenceExpression("value")));

            cClass.Members.Add(property1);
            cClass.Members.Add(property2);

            // constructor
            CodeConstructor cConstructor = new CodeConstructor();
            cConstructor.Attributes = MemberAttributes.Public;

            cConstructor.Parameters.Add(new CodeParameterDeclarationExpression("Int32", "length"));
            cConstructor.Parameters.Add(new CodeParameterDeclarationExpression("Int32", "width"));

            cConstructor.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeThisReferenceExpression(), "Length"),
                new CodeArgumentReferenceExpression("length")));

            cConstructor.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeThisReferenceExpression(), "Width"),
                new CodeArgumentReferenceExpression("width")));

            cClass.Members.Add(cConstructor);

            // CalculateArea() method
            CodeMemberMethod cMethod = new CodeMemberMethod();
            cMethod.Name = "CalculateArea";
            cMethod.Attributes = MemberAttributes.Public;
            cMethod.ReturnType = new CodeTypeReference("Int32");

            cMethod.Statements.Add(new CodeVariableDeclarationStatement(typeof(int), "area",
                new CodeSnippetExpression("Length * Width")));

            //cMethod.Statements.Add(new CodeSnippetExpression("return area"));
            cMethod.Statements.Add(new CodeMethodReturnStatement(
                new CodeVariableReferenceExpression("area")));

            cClass.Members.Add(cMethod);

            // Main() method
            CodeEntryPointMethod mainMethod = new CodeEntryPointMethod();

            mainMethod.Statements.Add(new CodeVariableDeclarationStatement("Rectangle", "rectClass",
                new CodeObjectCreateExpression("Rectangle",
                    new CodePrimitiveExpression(5),
                    new CodePrimitiveExpression(4))));
            mainMethod.Statements.Add(new CodeVariableDeclarationStatement(typeof(int), "area",
                new CodeSnippetExpression("rectClass.CalculateArea()")));

            mainMethod.Statements.Add(new CodeMethodInvokeExpression(
                new CodeTypeReferenceExpression("Console"), "WriteLine",
                new CodeVariableReferenceExpression("area")));
            // mainMethod.Statements.Add(new CodeSnippetExpression("System.Console.WriteLine(area)"));

            cClass.Members.Add(mainMethod);

            CodeCompileUnit comUnit = new CodeCompileUnit();
            comUnit.Namespaces.Add(cNamespace);
            return comUnit;
        }

        private static CodeDomProvider GetCodeDomProvider(string language)
        {
            CodeDomProvider codeProvider;
            language = language.ToUpper();

            if (language == "CSHARP")
                codeProvider = new CSharpCodeProvider();
            else if (language == "VBNET")
                codeProvider = new VBCodeProvider();
            else
                throw new ArgumentException("'{0}' language is not supported", language);

            return codeProvider;
        }
        private static void GenerateCode(CodeCompileUnit comUnit, TextWriter textWriter, string language)
        {
            CodeDomProvider codeProvider = GetCodeDomProvider(language);

            CodeGeneratorOptions genOptions = new CodeGeneratorOptions();
            genOptions.IndentString = "  ";

            codeProvider.GenerateCodeFromCompileUnit(comUnit, textWriter, genOptions);
        }

        private static void GenerateExecutableFile(CodeCompileUnit comUnit, string language)
        {
            CodeDomProvider codeProvider = GetCodeDomProvider(language);

            CompilerParameters comParam = new CompilerParameters();
            comParam.GenerateExecutable = true;
            comParam.OutputAssembly = "Rectangle.exe";
            comParam.GenerateInMemory = false;

            CompilerResults comResults = codeProvider.CompileAssemblyFromDom(comParam, comUnit);
            if (comResults.Errors.Count > 0)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                foreach (CompilerError ce in comResults.Errors)
                {
                    Console.WriteLine("Line: {0}: Error Number:{1}\n{2}", ce.Line, ce.ErrorNumber, ce.ErrorText);
                }
                Console.ResetColor();
            }
        }

        public static void Main()
        {
            Program test = new Program();
            CodeCompileUnit comUnit = test.CreateRectangleCode();
            //string language="csharp";
            string language = "vbnet";

            StringBuilder strBuilder = new StringBuilder();
            StringWriter writer = new StringWriter(strBuilder);
            //StreamWriter writer= new StreamWriter("C:\\a.cs");
            //writer.AutoFlush = true;

            GenerateCode(comUnit, writer, language);
            Console.WriteLine(strBuilder.ToString());

            GenerateExecutableFile(comUnit, language);
            Console.Read();
        }
    }
}

Output:

CodeDom Example

Tham khảo bài viết:

.Net – CodeDOM – Tìm hiểu và ứng dụng

One thought on “CodeDom – Dynamic Code Generation: Rectangle Class

Gửi phản hồi

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s