久しぶりにC#でEvalしたよ。というか対話式シェルっぽいの作ってみた。
途中まで昔に作ってたんだけど、変数の値を保存する仕組みがなくてお蔵入りにしてたやつ。
とりあえず変数の値は保存できるようになりました。そのかわりコンソールに値出力するときはConsole.WriteLine呼ばないと出力できません。
毎回値表示して返せたらいいんだろうけどなぁ。。。
実行したコードはConsole.WriteLine以外全部保存してメソッド作り直しています。気持ち悪いなぁ。
コードは全部でこんだけ。らくちん。
using System; using System.Collections.Generic; using System.Text; using Microsoft.CSharp; using System.CodeDom.Compiler; using System.Reflection; class Program { static List<string> CodeList = new List<string>(); static void Main(string[] args) { Console.Title = "eval c#"; //Console.InputEncoding = Encoding.Unicode; if(Console.CapsLock) { Console.WriteLine("CapsLock:On"); } else { Console.WriteLine("CapsLock:Off"); } if(Console.NumberLock) { Console.WriteLine("NumLock:On"); } else { Console.WriteLine("NumLock:Off"); } Console.WriteLine("終わるときは exit てタイプしてください。"); string s = String.Empty; while((s = Console.ReadLine()) != "exit") { LineEval(s); } } private static bool NotIn(string st,params string[] items) { foreach(string item in items) { if(st == item) { return false; } } return true; } public static object LineEval(string sCSCode) { CSharpCodeProvider c = new CSharpCodeProvider(); ICodeCompiler icc = c.CreateCompiler(); CompilerParameters cp = new CompilerParameters(); cp.ReferencedAssemblies.Add("system.dll"); cp.ReferencedAssemblies.Add("system.xml.dll"); cp.ReferencedAssemblies.Add("system.data.dll"); cp.ReferencedAssemblies.Add("system.windows.forms.dll"); cp.ReferencedAssemblies.Add("system.drawing.dll"); cp.CompilerOptions = "/t:library"; cp.GenerateInMemory = true; StringBuilder sb = new StringBuilder(""); sb.Append("using System;\n"); sb.Append("using System.Xml;\n"); sb.Append("using System.Data;\n"); sb.Append("using System.Data.SqlClient;\n"); sb.Append("using System.Windows.Forms;\n"); sb.Append("using System.Drawing;\n"); sb.Append("namespace CSCodeEvaler{ \n"); sb.Append("public class CSCodeEvaler{ \n"); sb.Append("private void __Print(object ob){}\n"); sb.Append("public void EvalCode(){\n"); foreach(string ss in CodeList) { sb.Append(ss); } //sb.Append(" Console.WriteLine(" + sCSCode + "); \n"); sb.Append(sCSCode); sb.Append("} \n"); sb.Append("} \n"); sb.Append("}\n"); CompilerResults cr = icc.CompileAssemblyFromSource(cp,sb.ToString()); if(cr.Errors.Count > 0) { Console.WriteLine("ERROR: " + cr.Errors[0].Line + "行目:" + cr.Errors[0].ErrorText); return null; } else { sCSCode = sCSCode.Replace("System.Console.WriteLine","__Print"); sCSCode = sCSCode.Replace("Console.WriteLine","__Print"); CodeList.Add(sCSCode); } System.Reflection.Assembly a = cr.CompiledAssembly; object o = a.CreateInstance("CSCodeEvaler.CSCodeEvaler"); Type t = o.GetType(); MethodInfo mi = t.GetMethod("EvalCode"); object s = mi.Invoke(o,null); return s; } }
追記
あぁ、これあれだ
副作用あるメソッド呼ぶとやばい 笑い
やっぱいったんパースしてやるしかないかなぁ?