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

動態編譯入門(一):CSharpCodeProvider 運行時編譯 C# 字串為組件

     編輯:關於C#

動態編譯** = 在程式運行期間,將 C# 代碼字串編譯成組件,再透過反射調用其中的成員。類似 SQL EXEC('...') 或 JS eval(),但具備強型別、編譯期檢查、IDE 支援等優勢。

為什麼要用動態編譯?

  • 計算使用者輸入的公式字串(如 "2+3*(4-1)/5%7")
  • 運行時依配置生成特定邏輯(規則引擎、映射器、序列化器)
  • 效能熱路徑:將反射/解譯器改為編譯原生 IL
  • 極致擴展性:外部腳本即插即用

注意:編譯組件無法卸載、首次編譯較慢,**僅適用於「高頻重複呼叫」的熱路徑**。一次性計算請用 DataTable.Compute 或表達式樹。

核心類別:CSharpCodeProvider


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

public class DynamicCompile_1 {
    public static Assembly CompileAssembly(string code, params Type[] usingTypes) {
        var cp = new CompilerParameters {
            GenerateExecutable = false,
            GenerateInMemory = true
        };

        var ns = new HashSet<string>();
        foreach (var t in usingTypes) {
            ns.Add("using " + t.Namespace + ";" + Environment.NewLine);
            cp.ReferencedAssemblies.Add(t.Module.FullyQualifiedName);
        }
        code = string.Concat(ns) + code; // 自動補 using

        using (var provider = new CSharpCodeProvider()) {
            var cr = provider.CompileAssemblyFromSource(cp, code);
            if (cr.Errors.HasErrors) {
                var sb = new StringBuilder("編譯錯誤:");
                foreach (CompilerError err in cr.Errors) sb.AppendLine(err.ErrorText);
                throw new Exception(sb.ToString());
            }
            return cr.CompiledAssembly;
        }
    }
}

最小範例:計算公式字串


public static decimal Calculate(string formula) {
    string code = $@"
public class Class1 {{
    public static decimal GetValue() {{
        return (decimal)({formula});
    }}
}}";
    // 傳入公式用到的型別(decimal)
    Type type = DynamicCompile_1.CompileAssembly(code, typeof(decimal))
        .GetType("Class1");
    return (decimal)type.GetMethod("GetValue").Invoke(null, null);
}

// 測試
var result = Calculate("2 + 3 * (4 - 1) / 5 % 7"); // = 2
Console.WriteLine(result);

關鍵細節

項目說明
GenerateInMemory = true不產生實體 DLL,直接在記憶體組件
ReferencedAssemblies必須加入代碼用到的所有型別所在組件
自動補 using用 HashSet 去重命名空間,避免重複
錯誤處理CompilerResults.Errors 收集編譯錯誤並拋出

適用 .NET 版本

  • .NET Framework 2.0+ 內建 System.CodeDom.Compiler
  • .NET Core / .NET 5+ 需引用 Microsoft.CodeAnalysis.CSharp.Scripting (Roslyn) 或 System.CodeDom 相容包

這就是動態編譯的「Hello World」。下一篇將實戰:手寫 JSON 序列化器,對比反射與動態編譯效能。

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