だらだらやるよ。

こげつのIT技術メモ

久しぶりに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;
	}
}

追記
あぁ、これあれだ
副作用あるメソッド呼ぶとやばい 笑い
やっぱいったんパースしてやるしかないかなぁ?