前面说了这么多,大家可能会觉得,好像没弄出个玩意儿来啊,对啊,所以,本文就来个可以弄出个玩意儿的东东。
说明一下,这是一个综合示例,分为两大部分,第一部分,生成代码,输出到控制台窗口中;第二部分,把这些代码动态进行编译,并生成一个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(); } } }
运行程序,代码生成完成,并且成功编译,如下图所示。
那么,生成的WinForm程序在哪儿呢?上面代码中使用了 /out:Myapp.exe 参数,那么这个EXE在哪呢,相对路径,也就是和当前应用程序在同一个目录,现在,打开你的项目所在的位置,找到 \bin\Debug,看到那个Myapp.exe没?看到了就双击运行。好的,奇迹的一刻发生了。
怎么样?这回该有点玩意儿了吧?
总结一下,这个动态生成代码,说实话,平时用到它的机会不多,所以,我也没详细讲述,再者,用起来也不复杂,痛苦的是思路。所以,有人问,这个动态生成或动态编译在实际应用中有啥用处?呵呵,开玩笑地回答你:做木马!呵呵。