NET脚本编译CodeDomCompiler
2018-09-14

0X1 摘要

动态编译和执行C#脚本

0X2 参数说明

参数 说明
code 要编译的脚本
function 需要执行的方法
invoker 成功编译后的执行器
matcher 方法完整匹配(非必须)

0X3 使用

脚本

public string Format(string year)
{
    var x = new System.Text.StringBuilder(200);
    var t = new System.DateTime();
    //var s = $"{year}--name";
    var s = string.Format("{0}--name", year);
    return s;
}

执行

 if (TryCompile(doc, "Format", out var invoker,
  "System.String Format(System.String)"))
{
    var res = invoker.Invoke(new object[] { "2018902-02" });
    Console.WriteLine(res);
}

输出

2018902-02--name

0X4 源

public bool TryCompile(string code, string function, out Func<object[], object> invoker, string matcher = null)
{
    invoker = null;
    if (string.IsNullOrEmpty(code)) return false;
    if (!code.Contains(function)) return false;
    const string _name = "_TempScript";
    StringBuilder builder = new StringBuilder(code.Length + 20);
    builder.AppendLine("using System;");
    builder.AppendLine("namespace _tempNamespace{");
    builder.Append($"class {_name}");
    builder.AppendLine("{");
    builder.AppendLine(code);
    builder.AppendLine("}}");

    using (CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"))
    {
        CompilerParameters option = new CompilerParameters
        {
            GenerateExecutable = false,
            GenerateInMemory = true,
            TreatWarningsAsErrors = false,
            IncludeDebugInformation = false,
            OutputAssembly = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, _name + ".tmp")
        };
        CompilerResults cr = provider.CompileAssemblyFromSource(option, new string[] { builder.ToString() });
        if (cr.Errors.HasErrors)
        {
            Console.WriteLine("编译错误:");
            foreach (CompilerError err in cr.Errors)
                Console.WriteLine(err.ErrorText);
            return false;
        }
        Assembly _assembly = cr.CompiledAssembly;
        TypeInfo _type;
        using (var e = _assembly.DefinedTypes.GetEnumerator())
        {
            e.MoveNext();
            _type = e.Current;
        }
        MethodInfo _method = _type.GetMethod(function);
        if (_method == null) { Console.WriteLine("未找到指定方法"); return false; }
        if (matcher != null && !matcher.Equals(_method.ToString(), StringComparison.OrdinalIgnoreCase))
        { Console.WriteLine("指定方法结构与预期不一致"); return false; }
        var obj = Activator.CreateInstance(_type);
        invoker = (parameters) => _method.Invoke(obj, parameters);
        return true;
    }
}