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

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

例如:js中的代码:

eval("alert('hello world');");  

将会弹出一个写有hello world的提示框。

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

Google了一下,网站http://www.ckode.dk/programming/eval-in-c-yes-its-possible/基本实现了两个参数的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!
时间: 2024-11-08 00:22:21

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

Java 集合、数组 任意个数数字相加等于一个指定的数

一组数字 任意个数数字相加的和等于指定的数字.  比如数字集合 1,2,3, 4,5,6  ,列出所有数字相加等于6的可能性,那么结果有:1+2+3,2+4, 主要这里的结果不是数组打乱顺序相加,而是按照数组顺序取任意个数相加减,所有大家看到结果只有1+2+3而没有1+3+2或则3+2+1 step1.实体类: static class TestDTO { String id; //id Integer num;//数字 public String getId() { return id; }

C#实现整型数据字任意编码任意进制的转换和逆转换

实现如下: using System; using System.Collections.Generic; using System.Linq; using System.Text;  namespace ConsoleApplication1 {      public class Number     {         public string Characters         {             get;             set;         }        

基类中定义的虚函数在派生类中重新定义时,其函数原型,包括返回类型、函数名、参数个数、参数类型及参数的先后顺序,都必须与基类中的原型完全相同 but------&gt; 可以返回派生类对象的引用或指针

您查询的关键词是:c++primer习题15.25 以下是该网页在北京时间 2016年07月15日 02:57:08 的快照: 如果打开速度慢,可以尝试快速版:如果想更新或删除快照,可以投诉快照. 百度和网页 http://bbs.csdn.net/topics/380238133 的作者无关,不对其内容负责.百度快照谨为网络故障时之索引,不代表被搜索网站的即时页面. 首页 精选版块 移动开发 iOS Android Qt WP 云计算 IaaS Pass/SaaS 分布式计算/Hadoop J

C# 给某个方法设定执行超时时间 C#函数运行超时则终止执行(任意参数类型及参数个数通用版)

在某些情况下(例如通过网络访问数据),常常不希望程序卡住而占用太多时间以至于造成界面假死. 在这时.我们可以通过Thread.Thread + Invoke(UI)或者是 delegate.BeginInvoke 来避免界面假死, 但是这样做时,某些代码或者是某个方法的执行超时的时间还是无法操控的.那么我们又是否有一种比较通用的方法.来设定某一个方法的执行超时的时间,让该其一旦超过指定时间则跳出指定方法.进而继续向下执行呢? 答案当然是肯定的. delegate.BeginInvoke可以实现代

shell脚本计算任意个数的加减乘除

#!/bin/bash if [ $# -eq 0 ]; then  echo "输入值不能为空"          //提示不能输入空值  注:$#代表环境变量个数  exit fi num=$*                       //定义一个全局变量,方便后边的调用 sum() { sum=0 while [ $# -gt 0 ] do   sum=$[ $sum+$1 ]   shift done echo  "数字 $num 相加的和是 $sum"

小程序-----可以计算任意个数数字的加、乘运算方法实现

1 public class Text1{ 2 public static void main(String args[]){ 3 System.out.println("和等于:"+add(2,5)); 4 System.out.println("和等于:"+add(2,5,100,25,23)); 5 System.out.println("和等于:"+add()); 6 System.out.println("乘等于:"

Autolayout环境设置任意个数相等间距排列的按钮的方法

首先,来看一下做成后的效果: 实现步骤如下: 1.在storyboard中放置四个按钮,并同时选中它们. 2.设置好宽.高.supview下边界的距离等约束 3.设置完成 4.选中第一个按钮 5.设置它距左边界的约束. 6.设置第二个.以此类推. 7.在代码中写好IBoutlet,分别是四个按钮到边的约束和其中一个按钮的宽度约束. 8.选中Viewcontroller 9.选择"关系标签" 10.开始联线 10.在ViewController中写下如下代码 11.搞定.

使用可变参数列表实现任意个数求平均值

#include <stdio.h> #include <stdarg.h> int average(int val,...) {   int i=0;   int sum=0;   va_list arg;   va_start(arg,val);     for(i=0;i<val;i++)   {     sum+=va_arg(arg, int);   }   va_end(arg);   return sum/val; } int main() {   int re

取任意范围内的,任意个数的随机数

这是取随机数的常用方法,是采用原生js编写.在一些动画特效以及活动中经常用到,分享一个简单的方法供大家参考. 1 function randomNub(aArray,len,min,max){ 2 //5排序 3 if(aArray.length>=len){ 4 aArray.sort(function(a,b){ 5 return a-b 6 }); 7 return aArray; 8 } 9 //1.取随机数 10 var nowNub = parseInt(Math.random()*