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

C# 實作 Eval 動態執行字串程式碼:利用 CodeDom 編譯器打造腳本引擎

     編輯:關於C#

為什麼需要 Eval?

JavaScript 的 eval() 能在執行期動態解析並執行字串程式碼,極適合規則引擎、使用者自訂腳本、動態報表等場景。C# 作為靜態編譯語言雖無內建 Eval,但透過 System.CodeDom.Compiler 命名空間,可在執行期動態編譯 C# 程式碼並呼叫,達到相同效果。

核心實作原理

  1. 將使用者傳入的程式碼片段包裝在預先定義的類別/方法模板中。
  2. 使用 CSharpCodeProvider 在記憶體中編譯組件 (GenerateInMemory = true)。
  3. 透過反射 Assembly.GetType() 取得動態類別,再用 InvokeMember 呼叫目標方法。
  4. 捕捉編譯錯誤與執行期例外,回饋給呼叫端。

完整程式碼實作

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

namespace CSHARP_EVAL_FUNCTION {
    public class EVAL {
        private static string prefix = @"
            using System;
            public static class DynamicClass {
                public static void Bomb() {";
        private static string postfix = @"}}";

        public string Content { get; set; }

        public void Eval() {
            if (string.IsNullOrEmpty(Content)) {
                Console.WriteLine("必須為 Content 屬性賦予值");
                return;
            }

            string code = prefix + Content + postfix;
            CompilerResults result = null;

            using (var provider = new CSharpCodeProvider()) {
                var options = new CompilerParameters {
                    GenerateInMemory = true,
                    TreatWarningsAsErrors = false
                };

                result = provider.CompileAssemblyFromSource(options, code);

                if (result.Errors.HasErrors) {
                    var errorMsg = new StringBuilder();
                    foreach (CompilerError error in result.Errors) {
                        errorMsg.AppendFormat("Line:{0}, Column:{1}, Error:{2}\n",
                            error.Line, error.Column, error.ErrorText);
                    }
                    Console.WriteLine("編譯錯誤:\n" + errorMsg);
                } else {
                    Type dynamicClass = result.CompiledAssembly.GetType("DynamicClass");
                    dynamicClass.InvokeMember("Bomb",
                        BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public,
                        null, null, null);
                }
            }
        }
    }
}

使用範例

var eval = new EVAL();
eval.Content = @"
    Console.WriteLine(""Hello from dynamic code!"");
    int x = 10, y = 20;
    Console.WriteLine($""Sum: {x + y}"");";
eval.Eval();
// 輸出:
// Hello from dynamic code!
// Sum: 30

進階擴充建議

  • 支援回傳值:將模板方法改為 public static TResult Eval<TResult>(),搭配 Func<TResult> 委派。
  • 沙箱隔離:使用 AppDomain 或 .NET Core 的 AssemblyLoadContext 限制動態程式碼權限。
  • 效能優化:快取編譯後的組件,避免重複編譯相同程式碼;考慮使用 Roslyn CSharpScript 取代 CodeDom (已淘汰)。
  • 命名空間引入:允許使用者指定 using 陳述式,擴充可用 API。

注意事項

CodeDom 僅支援 .NET Framework;.NET Core / .NET 5+ 請改用 Roslyn Scripting API (Microsoft.CodeAnalysis.CSharp.Scripting),效能更好且支援跨平台。動態編譯涉及安全風險,嚴禁直接執行不可信輸入,生產環境務必實施輸入驗證與沙箱機制。

步驟1
步驟2
步驟3
步驟4

原始碼下載:CSDN 下載連結

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved