今天在論壇裡面逛發現一個問題比較典型,我們在使用js的時候可以直接使用Eval得到某一個表達式的值,在C#裡面可以嗎?答案是肯定的,在.NET提供的豐富的類庫裡面這是可以實現的,但是沒有js那麼簡單下面我將使用一個簡單的例子來說明利用編譯器和反射得到一個字符串表達式的值。我們建立一個Windows窗體裡面有如下的方法:
引用一下命名空間:
using System;
using System.Text;
using System.CodeDom.Compiler;
using System.Reflection;
using System.IO;
using Microsoft.CSharp;
命名空間的具體意義就不說了,下面看看代碼,為了可以讓我們的工程可以重復使用我們新建一個類庫工程名叫:CoustomEval其中有一個類是用來計算某一斷字符串的值。詳細代碼如下所示:
namespace CoustomEval{
///
/// Summary description for Class1.
///
public class MyEval{
public MyEval(){
//
// TODO: Add constructor logic here
//
}
public object Eval(string cCharpCode){
CSharpCodeProvider csharpCodeProvider = new CSharpCodeProvider();
ICodeCompiler compiler = csharpCodeProvider.CreateCompiler();
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("system.dll");
cp.CompilerOptions = "/t:library";
cp.GenerateInMemory = true;
StringBuilder myCode = new StringBuilder();
myCode.Append("using System;");
myCode.Append("namespace CoustomEval{");
myCode.Append("class myLib {private "+cCharpCode+" public int myMethod(){return i;}}");
myCode.Append("}");
CompilerResults cr = compiler.CompileAssemblyFromSource(cp,myCode.ToString());
Assembly assembly = cr.CompiledAssembly;
object tmp = assembly.CreateInstance("CoustomEval.myLib");
Type type = tmp.GetType();
MethodInfo mi = type.GetMethod("myMethod");
object result = mi.Invoke(tmp,null);
return result;
}
}
}
上面的類庫只具有一般代表性不具備一般使用性,重要的是提供一種方法來實現它,所以我在裡面使用了硬編碼的方式,如果你喜歡可以使用其他的方式,包括讀文件,讀數據庫取得代碼段等等。然後我們在建立一個測試工程,該工程裡面有一個測試窗體,該窗體上有一個按鈕和兩個文本框,其中一個文文本框用來輸入要計算的值,另一個顯示計算的結果,詳細代碼如下:
private void button1_Click(object sender, System.EventArgs e) {
MyEval eval = new MyEval();
object result = eval.Eval(this.textBox1.Text);
this.textBox2.Text = result.ToString();
}
在這個工程中需要引用上面的工程,這樣我們就可以使用MyEval類來實現計算TextBox1裡面的值了,最後可以將值顯示在TextBox2裡面,代碼運行的結果我在這裡就不帖了。只給出我的測試結果,由於該問題源於論壇所以我就是用論壇中原來的測試要求。
測試結果:在TextBox中輸入int i = 10;點擊Button1以後將會在TextBox2中顯示出10。
當然你可以使用更復雜的計算表達式!這裡的目的是為了給您指出實現該功能的做法,至於實現的復雜程度讀者可以自己決定。