用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();
}
}
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();
}
}