C#即时编译器技术测试

用visual studio编写测试程序需要新建solution,然后project,命名和存盘都是麻烦事。可以考虑写一个自己的编译环境。

通过 Microsoft.CSharp.CSharpCodeProvider() 对象的 CompileAssemblyFromSource(parameters,codes) 方法就能得到编译结果对象 CompilerResults;然后结果对象再通过反射机制 result.CompiledAssembly.GetType("Phoenix") 就可以通过编译生成的程序集包含Main方法的类型。然后你可以 Phoenix.GetMethod("Main").Invoke(null,new string[]{});呼叫输出结果。

原理上说无非是构造csc可编译的完整源代码,然后生成assembly,当然是以临时文件形式存盘的,然后用reflect解析执行Main方法输出结果,如果用WinForm,可以用Console.SetOut重定向输出结果到控件。

测试代码如下,程序会编译文本 Console.WriteLine(\"Phoenix, from ashes it was born!\");:并给出结果!

using System;

using System.CodeDom.Compiler;

public class MyClass

{

private static string GenerateCode(string userCode)

{

string namespaces =@"using System;using System.ComponentModel;using System.Text;using System.Text.RegularExpressions;using System.IO;using System.Collections;using System.Collections.Generic;using System.Windows.Forms;using System.Threading;using System.Reflection;";

string codeHead = @"

sealed class Phoenix

{

public static void Main()

{";

//userCode here

string codeTail = @"

}

}";

string compileCodes = namespaces + codeHead + userCode + codeTail;

return compileCodes;

}

private static CompilerResults Compile(string codes)

{

//CSharpCodeProvider

System.CodeDom.Compiler.CodeDomProvider compiler = new Microsoft.CSharp.CSharpCodeProvider();

//CompilerParameters

System.CodeDom.Compiler.CompilerParameters parameters = new CompilerParameters();

parameters.WarningLevel = 4;

parameters.GenerateExecutable = false;

parameters.GenerateInMemory = true;

parameters.ReferencedAssemblies.Add("System.dll");

parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");

//Compile: if successfully, we get the assembly with a temp filename

return compiler.CompileAssemblyFromSource(parameters,codes);

}

public static void Main()

{

string userCode = "Console.WriteLine(\"Phoenix, from ashes it was born!\");";

string compileCodes = GenerateCode(userCode);

//Compile the codes and get the CompilerResults OBJECT

System.CodeDom.Compiler.CompilerResults result = Compile(compileCodes);

if(result.Errors.HasErrors)

{

//here, we output the error to output OBJECT

foreach (CompilerError error in result.Errors) {

Console.WriteLine(error.Line + ":" + error.ErrorText);

}

Console.ReadKey();

return;

}

//output the result

Console.WriteLine(result.CompiledAssembly.FullName);

Type Phoenix = result.CompiledAssembly.GetType("Phoenix");

try

{

Phoenix.GetMethod("Main").Invoke(null,new string[]{});

}

catch(System.Reflection.TargetInvocationException ex)

{

Console.WriteLine(ex);

}

Console.ReadKey();

}

}