C#中仿eval功能

private   object   doit(string   methodname,   object[]   args)
{
          Type   t   =   this.GetType();
          System.Reflection.MethodInfo   mi   =   t.GetMethod(methodname);
          return   mi.Invoke(this,args);
}   

 

 

 

 

 

 

 

 

有時候需要表達式運算,如
String strExpression="-12 * ( - 2.2 + 7.7 ) - 44 * 2";

網上找的,一般是利用CodeDom,見
http://www.codeproject.com/csharp/runtime_eval.asp

簡化爲:
System.CodeDom.Compiler.ICodeCompiler comp = (new Microsoft.CSharp.CSharpCodeProvider().CreateCompiler());
System.CodeDom.Compiler.CompilerParameters cp = new System.CodeDom.Compiler.CompilerParameters();

object qswhEval2(string Expression){
StringBuilder code = new StringBuilder();
code.Append("using System; /n");
code.Append("namespace ADOGuy { /n");
code.Append(" public class _Evaluator { /n");
code.Append("    public object __foo() ");
code.Append("{ ");
code.AppendFormat("      return ({0}); ", Expression);
code.Append("}/n");
code.Append("} }");
System.CodeDom.Compiler.CompilerResults cr = comp.CompileAssemblyFromSource(cp, code.ToString());
System.Reflection.Assembly a = cr.CompiledAssembly;
object _Compiled = a.CreateInstance("ADOGuy._Evaluator");
System.Reflection.MethodInfo mi = _Compiled.GetType().GetMethod("__foo");
return mi.Invoke(_Compiled, null);
}


但用起來感覺很慢,畢竟需要實時編譯。

於是,就自己照數據結構書上寫了一種算法:
string Precede(string p, string q){
switch(p){
   case "+":
   case "-":return ("*/(".IndexOf(q)!=-1)?"<":">";
   case "*":
   case "/":return (q=="(")?"<":">";
   case "(":return (q==")")?"=":"<";
   case ")":return (q=="(")?"?":">";
   case "#":return (q=="#")?"=":"<";
}
return "?";
}
Double Operate(Double a,char o,Double b)
{
switch(o)
    {
      case '+':return a+b;
      case '-':return a-b;
      case '*':return a*b;
      case '/':return a/b;
    }
    return 0;
}

Object qswhEval1(string Expression){
/*************(qiushuiwuhen 2002-12-14)****************/
Stack nArr=new Stack(),oArr=new Stack();
int j=0;
Double a=0,b=0;
string w="";
char o;
MatchCollection arr=Regex.Matches(Expression.Replace(" ","")+"#",@"(((?<=(^|/())-)?/d+(/./d+)?|/D)");

oArr.Push('#');
w=Convert.ToString(arr[j++]);
while(!(w=="#"&&Convert.ToString(oArr.Peek())=="#")){
   if("+-*/()#".IndexOf(w)!=-1){
    switch(Precede(oArr.Peek().ToString(),w)){
     case "<":
       oArr.Push(w);
       w=Convert.ToString(arr[j++]);
       break;
     case "=":
       oArr.Pop();
       w=Convert.ToString(arr[j++]);
       break;
     case ">":
       o=Convert.ToChar(oArr.Pop());
       b=Convert.ToDouble(nArr.Pop());
       a=Convert.ToDouble(nArr.Pop());
       nArr.Push(Operate(a,o,b));
       break;
     default:
       return "Error";
       break;
     
    }
   }else{
    nArr.Push(w);
    w=Convert.ToString(arr[j++]);
   }
}
return nArr.Pop();
}

還有利用JScript的Eval的兩種算法
Microsoft.JScript.Vsa.VsaEngine ve=Microsoft.JScript.Vsa.VsaEngine.CreateEngine();
object qswhEval3(string Expression){
return Microsoft.JScript.Eval.JScriptEvaluate(Expression,ve);
}

object qswhEval4(string Expression){
return qswhJs.qswhEval.Eval(Expression);
}

第四種需先建立一js編譯爲dll,如下代碼
import System;

package qswhJs {
class qswhEval {
    static function Eval(Expression):Object { return eval(Expression); }
}
}

測試代碼如下:
void Page_Load(Object o,EventArgs ea){
String strExpression="-12 * ( - 2.2 + 7.7 ) - 44 * 2";
int i=0,c=100;
DateTime d1,d2;
cp.GenerateExecutable = false;
cp.GenerateInMemory = true;

d1=DateTime.Now;
for(i=0;i<c;i++)qswhEval1(strExpression);
d2=DateTime.Now;
Response.Write("方法一:對表達式分析 "+d2.Subtract(d1)+"<br>");

d1=DateTime.Now;
for(i=0;i<c;i++)qswhEval2(strExpression);
d2=DateTime.Now;
Response.Write("方法二:利用CodeCom "+d2.Subtract(d1)+"<br>");

d1=DateTime.Now;
for(i=0;i<c;i++)qswhEval3(strExpression);
d2=DateTime.Now;
Response.Write("方法三:利用Jscript+Vsa "+d2.Subtract(d1)+"<br>");

d1=DateTime.Now;
for(i=0;i<c;i++)qswhEval4(strExpression);
d2=DateTime.Now;
Response.Write("方法四:利用Jsc+Dll "+d2.Subtract(d1)+"<br>");
}

測試結果:

方法一:對表達式分析 00:00:00.1702448
方法二:利用CodeCom 00:00:23.7942144
方法三:利用Jscript+Vsa 00:00:00.1902736
方法四:利用Jsc+Dll 00:00:00.2403456

在此推薦第一種(如果要純CSharp的話)
和第三種(代碼簡單,功能更多)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章