深入浅出.NET代码生成系列(7):动态生成代码与编译综合示例

前面说了这么多,大家可能会觉得,好像没弄出个玩意儿来啊,对啊,所以,本文就来个可以弄出个玩意儿的东东。

说明一下,这是一个综合示例,分为两大部分,第一部分,生成代码,输出到控制台窗口中;第二部分,把这些代码动态进行编译,并生成一个WinForm应用程序,双击动态编译的程序可以运行起来,点击窗口上的按钮,会弹出一个对话框。

好,下面我把整个示例的代码贴出来,很简单,你就新建一个控制台应用程序就可以了。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.CodeDom;
using System.CodeDom.Compiler;

namespace Example
{
    class Program
    {
        static void Main(string[] args)
        {
            CodeCompileUnit MyUnit = new CodeCompileUnit();
            // 一个命名空间
            CodeNamespace MyNamespace = new CodeNamespace("MyApp");
            MyNamespace.Imports.Add(new CodeNamespaceImport("System"));
            MyNamespace.Imports.Add(new CodeNamespaceImport("System.Windows.Forms"));
            MyNamespace.Imports.Add(new CodeNamespaceImport("System.Drawing"));
            MyNamespace.Imports.Add(new CodeNamespaceImport("System.Text"));
            // 定义一个类
            CodeTypeDeclaration MyClass = new CodeTypeDeclaration("MainForm");
            MyClass.Attributes = MemberAttributes.Public;
            MyClass.BaseTypes.Add(new CodeTypeReference("Form"));
            CodeMemberField buttonField = new CodeMemberField("Button", "button1");
            buttonField.InitExpression = new CodePrimitiveExpression(null);
            MyClass.Members.Add(buttonField);
            // 构造函数
            CodeConstructor MyConstr = new CodeConstructor();
            // 实例化Button类
            MyConstr.Statements.Add(
                new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "button1"),
                    new CodeObjectCreateExpression("Button", new CodeExpression[] { })));
            // 为Button实例的相关属性赋值
            MyConstr.Statements.Add(new CodeAssignStatement(
                    new CodePropertyReferenceExpression(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "button1"), "Text"),
                    new CodePrimitiveExpression("请点击这里")
                ));
            MyConstr.Statements.Add(new CodeAssignStatement(
                    new CodePropertyReferenceExpression(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "button1"), "Width"),
                    new CodePrimitiveExpression((int)285)
                ));
            MyConstr.Statements.Add(new CodeAssignStatement(
                    new CodePropertyReferenceExpression(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "button1"), "Height"),
                    new CodePrimitiveExpression((int)65)
                ));
            MyConstr.Statements.Add(new CodeAssignStatement(
                    new CodePropertyReferenceExpression(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "button1"), "Location"),
                    new CodeObjectCreateExpression("Point", new CodePrimitiveExpression((int)60), new CodePrimitiveExpression((int)80))
                ));
            // 绑定Button的Click事件
            MyConstr.Statements.Add(new CodeAttachEventStatement(
                    new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "button1"), "Click",
                    new CodeMethodReferenceExpression(new CodeThisReferenceExpression(), "button1_Click")
                ));
            // 设置窗口的宽度和高度
            MyConstr.Statements.Add(new CodeAssignStatement(
                    new CodePropertyReferenceExpression(new CodeThisReferenceExpression(),"Width"),
                    new CodePrimitiveExpression((int)450)
                ));
            MyConstr.Statements.Add(new CodeAssignStatement(
                    new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "Height"),
                    new CodePrimitiveExpression((int)300)
                ));
            // 设置窗口标题
            MyConstr.Statements.Add(new CodeAssignStatement(
                    new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "Text"),
                    new CodePrimitiveExpression("我的应用程序")
                ));

            // 将Button变量添加到Form的控件集合中
            MyConstr.Statements.Add(new CodeExpressionStatement(
                    new CodeMethodInvokeExpression(new CodePropertyReferenceExpression(new CodeThisReferenceExpression(),"Controls"),
                        "Add",
                        new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "button1"))
                ));
            MyClass.Members.Add(MyConstr);
            // 按钮单击处理程序
            CodeMemberMethod MyHandlerMethod = new CodeMemberMethod();
            MyHandlerMethod.Attributes = MemberAttributes.Private;
            MyHandlerMethod.Name = "button1_Click";
            MyHandlerMethod.Parameters.Add(new CodeParameterDeclarationExpression("Object", "sender"));
            MyHandlerMethod.Parameters.Add(new CodeParameterDeclarationExpression("EventArgs", "e"));
            // 方法中的描述
            MyHandlerMethod.Statements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(
                    new CodeTypeReferenceExpression("MessageBox"),
                    "Show",
                    new CodePrimitiveExpression("你好啊,欢迎点击。"))
                ));
            // 将方法添加到类成员中
            MyClass.Members.Add(MyHandlerMethod);
            // 将类添加到命名空间
            MyNamespace.Types.Add(MyClass);
            // 将命名空间添加到编译单元
            MyUnit.Namespaces.Add(MyNamespace);

            // 入口点函数
            CodeEntryPointMethod main = new CodeEntryPointMethod();
            main.Statements.Add(new CodeExpressionStatement(
                    new CodeMethodInvokeExpression(
                            new CodeTypeReferenceExpression("Application"),
                            "Run",
                            new CodeObjectCreateExpression("MainForm", new CodeExpression[] { })
                        )
                ));
            MyClass.Members.Add(main);

            // 输出生成的代码
            CodeDomProvider provider = CodeDomProvider.CreateProvider("cs");
            provider.GenerateCodeFromCompileUnit(MyUnit, Console.Out, new CodeGeneratorOptions { BracingStyle = "C" });
            
            // 编译程序集
            CompilerParameters param = new CompilerParameters();
            param.CompilerOptions = @"/t:winexe /out:Myapp.exe ";
            param.IncludeDebugInformation = false;
            param.ReferencedAssemblies.Add("mscorlib.dll");
            param.ReferencedAssemblies.Add("System.Drawing.dll");
            param.ReferencedAssemblies.Add("System.Windows.Forms.dll");
            param.ReferencedAssemblies.Add("System.dll");

            CompilerResults result = provider.CompileAssemblyFromDom(param, MyUnit);
            if (result.Errors.Count!=0)
            {
                Console.WriteLine("\n------------------- 编译错误 -------------------------- ");
                foreach (CompilerError err in result.Errors)
                {
                    Console.WriteLine("信息:{0}",err.ErrorText);
                }
            }
            else
            {
                Console.WriteLine("编译成功。");
            }
            Console.ReadKey();
        }
    }
}


运行程序,代码生成完成,并且成功编译,如下图所示。

深入浅出.NET代码生成系列(7):动态生成代码与编译综合示例_第1张图片

 

深入浅出.NET代码生成系列(7):动态生成代码与编译综合示例_第2张图片

那么,生成的WinForm程序在哪儿呢?上面代码中使用了 /out:Myapp.exe 参数,那么这个EXE在哪呢,相对路径,也就是和当前应用程序在同一个目录,现在,打开你的项目所在的位置,找到 \bin\Debug,看到那个Myapp.exe没?看到了就双击运行。好的,奇迹的一刻发生了。

深入浅出.NET代码生成系列(7):动态生成代码与编译综合示例_第3张图片

 

怎么样?这回该有点玩意儿了吧?

总结一下,这个动态生成代码,说实话,平时用到它的机会不多,所以,我也没详细讲述,再者,用起来也不复杂,痛苦的是思路。所以,有人问,这个动态生成或动态编译在实际应用中有啥用处?呵呵,开玩笑地回答你:做木马!呵呵。

 

 

你可能感兴趣的:(.net,object,application,System,button,WinForm)