首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 利用反射動態編譯執行字串運算式

     編輯:關於C#

問題背景

JavaScript 有 eval() 直接執行字串運算式,C# 能做到嗎?答案是肯定的。透過 System.CodeDom.Compiler 與反射,可在執行時動態編譯並執行 C# 程式碼片段。

核心實作:自訂 Eval 元件

using System;
using System.Text;
using System.CodeDom.Compiler;
using System.Reflection;
using System.IO;
using Microsoft.CSharp;

namespace CoustomEval
{
    public class MyEval
    {
        public object Eval(string cSharpCode)
        {
            var provider = new CSharpCodeProvider();
            var compiler = provider.CreateCompiler();
            var parameters = new CompilerParameters
            {
                ReferencedAssemblies = { "system.dll" },
                CompilerOptions = "/t:library",
                GenerateInMemory = true
            };

            var code = new StringBuilder();
            code.AppendLine("using System;");
            code.AppendLine("namespace CoustomEval {");
            code.AppendLine("  public class MyLib {");
            code.AppendLine("    private " + cSharpCode); // 例如:int i = 10;
            code.AppendLine("    public int MyMethod() { return i; }");
            code.AppendLine("  }");
            code.AppendLine("}");

            var results = compiler.CompileAssemblyFromSource(parameters, code.ToString());
            var assembly = results.CompiledAssembly;
            var instance = assembly.CreateInstance("CoustomEval.MyLib");
            var method = instance.GetType().GetMethod("MyMethod");
            return method.Invoke(instance, null);
        }
    }
}

WinForms 測試程式

private void btnCalculate_Click(object sender, EventArgs e)
{
    var eval = new MyEval();
    object result = eval.Eval(txtExpression.Text); // 輸入:int i = 10;
    txtResult.Text = result.ToString(); // 顯示:10
}

測試結果

輸入運算式輸出結果
int i = 10;10
int x = 5; int y = 3; int z = x * y + 2;17
double r = Math.Sqrt(16);4

關鍵技術點解析

  • CSharpCodeProvider:Roslyn 前身,提供執行時編譯能力。
  • CompilerParameters:GenerateInMemory=true 避免產生實體 DLL 檔案。
  • 動態命名空間/類別包裝:將使用者代碼包裝在完整類別結構中編譯。
  • 反射調用:CreateInstance → GetMethod → Invoke 完整鏈路。

⚠️ 生產環境考量

  • 效能開銷大:每次呼叫都編譯組件,不適合高頻熱路徑。
  • 安全風險:執行任意代碼需極度謹慎,嚴禁直接暴露給不可信輸入。
  • 現代替代方案:.NET Core / .NET 5+ 建議使用 Roslyn Scripting API (Microsoft.CodeAnalysis.CSharp.Scripting) 或 Expression Trees 獲得更好效能與安全性。

擴展建議

  • 支援多行語句、變數宣告、方法呼叫
  • 預載入常用命名空間 (System.Math, System.Linq 等)
  • 快取編譯結果(以運算式字串為 Key)避免重複編譯
  • 沙箱隔離:限制可存取的 API、執行時間、記憶體
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved