五一时去朋友那, 他问了个小问题, 只要写几十行代码就可以很好的说明问题.可偏偏机子没装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]);
}
}
}