五一时去朋友那, 他问了个小问题, 只要写几十行代码就可以很好的说明问题.可偏偏机子没装VS, 只好做罢.回来后想想, 要是有个在线的C#IDE就好了.于是上网查了下相关的资料, 整出来个简单的在线C#IDE.
做这个,主要要解决两个问题, 一是如果将网页上文本框的代码编译并执行;二是如果将程序运行结果在网页上输出.
第一个问题不难, .NET已经有现成的C#编译类CSharpCodeProvider(或是其它语言的),再使用CompilerParameters类做为编译参数,就可以很容易的实现.
第二个问题, 举最简单情况, 就是将Console.Write方法输出的内容在网页上显示出来.这其实也很好办,只要在编译之前, 在输出语句做一个替换, 将输出的内容存到另一个地方.等运行结束后, 再从那个地方取出来就是了.
代码实现如下:
| 以下是引用片段: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace VSOnline.Framework { /**//// /// 自定义的输出类 /// public class Consoler { //存储所有输出 public static Dictionary Outputs { get; set; } static Consoler() { Outputs = new Dictionary(); } 输出操作#region 输出操作 //当前输出 public List Output { get; private set; } public Consoler() { Output = new List(); } public void Write(object str) { Output.Add(str.ToString()); } public void WriteLine(object str) { Output.Add(str.ToString() + "\n"); } #endregion } } using System; using System.Reflection; using Microsoft.CSharp; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Linq; using System.Web; namespace VSOnline.Framework { /**//// /// 代码执行类 /// public class CodeRun { /**//// /// Framework版本,可选择v2.0, v3.0, v3.5 /// private string CompilerVersion { get; set; } /**//// /// 构造函数 /// /// Framework版本,可选择v2.0, v3.0, v3.5 public CodeRun(string compilerVersion) { CompilerVersion = compilerVersion; } /**//// /// 构造函数,默认为3.5版本 /// public CodeRun() { CompilerVersion = "v3.5"; } /**//// /// 动态编译并执行代码 /// /// 代码 /// 返回输出内容 public List Run(string code, string id, params string[] assemblies) { Consoler.Outputs.Add(id, new Consoler()); CompilerParameters compilerParams = new CompilerParameters(); //编译器选项设置 compilerParams.CompilerOptions = "/target:library /optimize"; //compilerParams.CompilerOptions += @" /lib:""C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\"""; //编译时在内存输出 compilerParams.GenerateInMemory = true; //生成调试信息 compilerParams.IncludeDebugInformation = false; //添加相关的引用 foreach (string assembly in assemblies) { compilerParams.ReferencedAssemblies.Add(assembly); } compilerParams.ReferencedAssemblies.Add("mscorlib.dll"); compilerParams.ReferencedAssemblies.Add("System.dll"); if (this.CompilerVersion == "v3.5") { compilerParams.ReferencedAssemblies.Add("System.Core.dll"); } string path = ""; try { path = HttpContext.Current.Server.MapPath("/bin/"); } catch { } compilerParams.ReferencedAssemblies.Add(path + "VSOnline.Framework.dll"); CSharpCodeProvider compiler = new CSharpCodeProvider(new Dictionary() { { "CompilerVersion", CompilerVersion } }); //编译 code = code.Replace("Console.WriteLine", string.Format("VSOnline.Framework.Consoler.Outputs[\"{0}\"].WriteLine", id)); code = code.Replace("Console.Write", string.Format("VSOnline.Framework.Consoler.Outputs[\"{0}\"].Write", id)); CompilerResults results = compiler.CompileAssemblyFromSource(compilerParams, code); //错误 if (results.Errors.HasErrors) { foreach (CompilerError error in results.Errors) { Consoler.Outputs[id].Output.Add(error.ErrorText + "\n"); } return ReturnOutput(id); } //创建程序集 Assembly asm = results.CompiledAssembly; //获取编译后的类型 object mainClass = asm.CreateInstance("Program"); Type mainClassType = mainClass.GetType(); //输出结果 mainClassType.GetMethod("Main").Invoke(mainClass, null); return ReturnOutput(id); } private List ReturnOutput(string id) { string[] output = new string[Consoler.Outputs[id].Output.Count]; Consoler.Outputs[id].Output.CopyTo(output, 0); Consoler.Outputs.Remove(id); return output.ToList(); } } } |
| 以下是引用片段: using VSOnline.Framework; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Collections.Generic; using System; using FastDev.Core; using System.Linq; namespace Test { [TestClass()] public class CodeRunTest { [TestMethod()] public void RunTest() { CodeRun target = new CodeRun(); string code = @" using System; public class Program { public static void Main() { for(int index = 1;index <= 3;index++) { Console.Write(index); } } } "; List expected = new List() { "1", "2", "3" }; List actual; actual = target.Run(code, "1"); Assert.AreEqual(true, expected.SerializeEqual(actual)); actual = target.Run(code, "2"); Assert.AreEqual(true, expected.SerializeEqual(actual)); } [TestMethod()] public void Run35Test() { CodeRun target = new CodeRun(); string code = @" using System; using System.Collections; using System.Collections.Generic; using System.Linq; public class Program { public static string Name { get; set; } public static void Main() { Name = ""3""; Console.Write(Name); } } "; List actual; actual = target.Run(code, "1", "System.Core.dll"); Assert.AreEqual("3", actual[0]); } } } |

完整程序下载 : VSOnline.rar