前面说了这么多,大家可能会觉得,好像没弄出个玩意儿来啊,对啊,所以,本文就来个可以弄出个玩意儿的东东。
说明一下,这是一个综合示例,分为两大部分,第一部分,生成代码,输出到控制台窗口中;第二部分,把这些代码动态进行编译,并生成一个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没?看到了就双击运行。好的,奇迹的一刻发生了。
怎么样?这回该有点玩意儿了吧?
总结一下,这个动态生成代码,说实话,平时用到它的机会不多,所以,我也没详细讲述,再者,用起来也不复杂,痛苦的是思路。所以,有人问,这个动态生成或动态编译在实际应用中有啥用处?呵呵,开玩笑地回答你:做木马!呵呵。