创建一个简单的C#脚本引擎

码农总是有许许多多的脚本工具,但windows下的bat脚本实在承担不起太多的逻辑和功能,PowerShell又太过复杂,不想学。干脆做个简单的可以执行C#脚本的工具。

嗯,花了2小时写代码加调试,总算是完成了一个简单的版本,具备如下特征:

  1. 动态载入命令行参数指定的脚本
  2. 允许在命令行附加脚本参数
  3. 脚本namespace必须为Script,class必须为Program,主函数必须是public static void Main(string[] args)
  4. 脚本开发可用注释添加需要引入的程序集,例如//dll log4net.dll,引入的程序集必须位于脚本程序同目录下。

下附代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;
using System.IO;

namespace css {
	class Program {
		static void Main(string[] args) {
			if (args.Length == 0) {
				Usage();
				return;
			}
			if (!File.Exists(args[0])) {
				Console.WriteLine("Can't find {0}.", args[0]);
				return;
			}

			//read script file
			string lines = File.ReadAllText(args[0], Encoding.UTF8);
			IList<string> dlls = ParserUseDlls(lines);

			CSharpCodeProvider codePrivoder = new CSharpCodeProvider();

			CompilerParameters compilerParameters = new CompilerParameters();
			compilerParameters.ReferencedAssemblies.Add("mscorlib.dll");
			compilerParameters.ReferencedAssemblies.Add("System.dll");
			compilerParameters.ReferencedAssemblies.Add("System.Core.dll");
			string exe_path = Path.GetDirectoryName(typeof(Program).Assembly.Location);
			if (!exe_path.EndsWith("/")) exe_path += "/";
			for (int i = 0, n = dlls.Count; i < n; i++)
				compilerParameters.ReferencedAssemblies.Add(exe_path + dlls[i]);
			compilerParameters.GenerateExecutable = false;
			compilerParameters.GenerateInMemory = true;

			CompilerResults cr = codePrivoder.CompileAssemblyFromSource(compilerParameters, lines);
			if (cr.Errors.HasErrors) {
				Console.WriteLine("编译错误:");
				foreach (CompilerError err in cr.Errors) {
					Console.WriteLine(err.ErrorText);
				}
			}
			else {
				// 通过反射,调用脚本文件的Main函数
				Assembly objAssembly = cr.CompiledAssembly;
				object objProgram = objAssembly.CreateInstance("Script.Program");
				MethodInfo objMain = objProgram.GetType().GetMethod("Main");

				object[] sargs = new object[1];
				if (args.Length > 1) {
					sargs[0] = new string[args.Length - 1];
					Array.Copy(args, 1, (string[])sargs[0], 0, sargs.Length);
				}
				else sargs[0] = new string[0];
				Console.WriteLine(objMain.Invoke(objProgram, sargs));
			}
		}

		private const string DLL_PREFIX = "//dll ";
		static IList<string> ParserUseDlls(string lines) {
			var ret = new List<string>();
			bool line_flag = false;
			for (int i = 0, n = lines.Length, start = 0; i < n; i++) {
				char c = lines[i];
				if (c == '\r' || c == '\n') {
					if (line_flag) continue;
					else line_flag = true;
					string line = lines.Substring(start, i - start);
					if (line.StartsWith(DLL_PREFIX)) {
						ret.Add(line.Substring(DLL_PREFIX.Length));
					}
					else break;
				}
				else if (line_flag) {
					start = i;
					line_flag = false;
				}
			}
			return ret;
		}

		static void Usage() {
			Console.WriteLine("Usage: {0} <script>", Path.GetFileName(typeof(Program).Assembly.Location));
			Console.WriteLine("");
			Console.WriteLine("-------------Example--------------");
			Console.WriteLine("//dll log4net.dll");
			Console.WriteLine("using System;");
			Console.WriteLine("namespace Script {");
			Console.WriteLine("    public class Program {");
			Console.WriteLine("        public static void Main(string[] args) {");
			Console.WriteLine("            Console.WriteLine(\"Hello World!\");");
			Console.WriteLine("        }");
			Console.WriteLine("    }");
			Console.WriteLine("}");
			Console.WriteLine("");
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值