C# 实现eval,支持任意个数、任意基本类型的参数

js中有一个方法eval,能够随时执行用户编写的代码。

例如:js中的代码:

eval("alert('hello world');"); 将会弹出一个写有hello world的提示框。

但C#中却没有对应的方法。

Google了一下,网站基本实现了两个参数的eval。但是,对于不定参数并不适用。其实编写C#版的eval的难点在于c#是强类型语言。琢磨了许久,终于碰巧写出了。以下是相关类:

using System;using System.CodeDom.Compiler;using System.Collections.Generic;using System.Linq;using System.Text;using System.Reflection;using Microsoft.CSharp;public class Arg{public string _type;public string _name;public Arg(string type, string name){this._type = type;this._name = name;}}public class EvalProvider{private string errorMessage = "";public string getErrorMessage(){return this.errorMessage;}public MethodInfo CreateMethod(List<Arg> args, Type returnType, string code, string[] usingStatements = null, string[] assemblies = null){var includeUsings = new HashSet<string>(new[] { "System" });includeUsings.Add(returnType.Namespace);string argStr = "";foreach (var arg in args){try{Type t = GetTypeByString(arg._type);includeUsings.Add(t.Namespace);argStr += ", " + arg._type + " " + arg._name;}catch{errorMessage = "uncompleted arg type: " + arg._type;return null;}}if (!argStr.Equals("")){argStr = argStr.Substring(2);}if (usingStatements != null)foreach (var usingStatement in usingStatements)includeUsings.Add(usingStatement);MethodInfo method;using (CSharpCodeProvider compiler = new CSharpCodeProvider()){var name = "F" + Guid.NewGuid().ToString().Replace("-", string.Empty);var includeAssemblies = new HashSet<string>(new[] { "system.dll" });if (assemblies != null)foreach (var assembly in assemblies)includeAssemblies.Add(assembly);var parameters = new CompilerParameters(includeAssemblies.ToArray()){GenerateInMemory = true};string source = string.Format(@"{0}namespace {1}{{public static class EvalClass{{public static {2} Eval({3}){{{4}}}}}}}", GetUsing(includeUsings), name, returnType.Name, argStr, code);var compilerResult = compiler.CompileAssemblyFromSource(parameters, source);var compiledAssembly = compilerResult.CompiledAssembly;var type = compiledAssembly.GetType(string.Format("{0}.EvalClass", name));method = type.GetMethod("Eval");}return method;}private string GetUsing(HashSet<string> usingStatements){StringBuilder result = new StringBuilder();foreach (string usingStatement in usingStatements){result.AppendLine(string.Format("using {0};", usingStatement));}return result.ToString();}/// <summary>/// 根据字符串获得类型,目前只适合简单类型。若是复杂类型,,可能会抛出异常/// </summary>/// <param name="type"></param>/// <returns></returns>public Type GetTypeByString(string type){switch (type.ToLower()){case "bool":return Type.GetType("System.Boolean", true, true);case "byte":return Type.GetType("System.Byte", true, true);case "sbyte":return Type.GetType("System.SByte", true, true);case "char":return Type.GetType("System.Char", true, true);case "decimal":return Type.GetType("System.Decimal", true, true);case "double":return Type.GetType("System.Double", true, true);case "float":return Type.GetType("System.Single", true, true);case "int":return Type.GetType("System.Int32", true, true);case "uint":return Type.GetType("System.UInt32", true, true);case "long":return Type.GetType("System.Int64", true, true);case "ulong":return Type.GetType("System.UInt64", true, true);case "object":return Type.GetType("System.Object", true, true);case "short":return Type.GetType("System.Int16", true, true);case "ushort":return Type.GetType("System.UInt16", true, true);case "string":return Type.GetType("System.String", true, true);case "date":case "datetime":return Type.GetType("System.DateTime", true, true);case "guid":return Type.GetType("System.Guid", true, true);default:return Type.GetType(type, true, true);}}}由于其中的方法GetTypeByString不能获得所有的类型,因此该C#版的eval不能支持所有的类型,只支持一些基本类型。

调用方法:

EvalProvider eval=new EvalProvider();List<Arg> argList = new List<Arg>();argList.Add(new Arg("int", "a"));argList.Add(new Arg("int", "b"));argList.Add(new Arg("string", "c"));var method= eval.CreateArgMethod(argList, eval.GetTypeByString("string"), @"return ""Hello world "" + (a + b) + c;");object result = method.Invoke(null, new object[] { 2, 2 , " never mind!"});Console.WriteLine((string)Convert.ChangeType(result, eval.GetTypeByString("string")));输出:

Hello world 4 never mind!

不敢面对自己的不完美,总是担心自己的失败,

C# 实现eval,支持任意个数、任意基本类型的参数

相关文章:

你感兴趣的文章:

标签云: