zoukankan      html  css  js  c++  java
  • 使用 Roslyn引擎动态编译代码

    Roslyn引擎自2014年开源至今这么久,一直没怎么了解过,虽然VS2015早就集成了它。

    以前老一套的动态编译方法在 .NET Core中似乎不再支持了,很多方法都是未实现的。下面就介绍如何在.NET Core环境中使用Roslyn进行动态编译。话不多说,Talk is cheap, show me the code.

    首先是安装nuget包

    Install-Package Microsoft.CodeAnalysis.CSharp 

    接下来是我们需要动态编译和执行的代码:

    // 表达式树
    SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(@"
        using System;
    
        namespace RoslynCompileSample
        {
            public class Writer
            {
                public void Write(string message)
                {
                    Console.WriteLine(message);
                }
            }
        }");

    紧接着是创建编译对象:

    // 随机程序集名称
    string assemblyName = Path.GetRandomFileName();
    
    // 元数据引用
    MetadataReference[] references = new MetadataReference[]
    {
        MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
        MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location)
    };
    
    // 创建编译对象
    CSharpCompilation compilation = CSharpCompilation.Create(
        assemblyName,
        syntaxTrees: new[] { syntaxTree },
        references: references,
        options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

    然后是编译:

    using (var ms = new MemoryStream())
    {
       // 将编译后的IL代码放入内存中
        EmitResult result = compilation.Emit(ms);
    
       // 编译失败,提示
        if (!result.Success)
        {
            IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic => 
                diagnostic.IsWarningAsError || 
                diagnostic.Severity == DiagnosticSeverity.Error);
    
            foreach (Diagnostic diagnostic in failures)
            {
                Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
            }
        }
        else
        {
            // 编译成功则从内存中加载程序集
            ms.Seek(0, SeekOrigin.Begin);
            Assembly assembly = Assembly.Load(ms.ToArray());
        }
    }

    最后则是调用:

    // 反射获取程序集中 的类
    Type type = assembly.GetType("RoslynCompileSample.Writer");
    
    // 创建该类的实例
    object obj = Activator.CreateInstance(type);
    
    // 通过反射方式调用类中的方法。(Hello World 便是我们传入方法的参数)
    type.InvokeMember("Write",
        BindingFlags.Default | BindingFlags.InvokeMethod,
        null,
        obj,
        new object[] { "Hello World" });

    最后咱们可以封装一个方法,以便于调用:

    /// <summary>
    /// 动态编译
    /// </summary>
    /// <param name="code">需要动态编译的代码</param>
    /// <returns>动态生成的程序集</returns>
    public static Assembly GenerateAssemblyFromCode(string code) 
    {
        Assembly assembly = null;
        // 丛代码中转换表达式树
        SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);
        // 随机程序集名称
        string assemblyName = Path.GetRandomFileName();
        // 引用
        var references = AppDomain.CurrentDomain.GetAssemblies().Select(x => MetadataReference.CreateFromFile(x.Location));
        
        // 创建编译对象
        CSharpCompilation compilation = CSharpCompilation.Create(assemblyName, new[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
        
        using (var ms = new MemoryStream()) 
        {
           // 将编译好的IL代码放入内存流
            EmitResult result = compilation.Emit(ms);
          
            // 编译失败,提示
            if (!result.Success) 
            {
                IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic => 
                            diagnostic.IsWarningAsError || 
                            diagnostic.Severity == DiagnosticSeverity.Error);
                foreach (Diagnostic diagnostic in failures) 
                {
                    Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
                }
            } 
            else 
            {
                // 编译成功,从内存中加载编译好的程序集
                ms.Seek(0, SeekOrigin.Begin);
                assembly = Assembly.Load(ms.ToArray());
            }
        }
        return assembly;
    }
  • 相关阅读:
    [洛谷P2463][SDOI2008]Sandy的卡片
    后缀数组
    周记【距gdoi:110天】
    hdu3068最长回文(Manacher算法)
    二分图的一些题目合集
    周记【距gdoi:117天】
    二分图、网络流模版总结
    2014end
    周记【距gdoi:126天】
    2-sat
  • 原文地址:https://www.cnblogs.com/WinHEC/p/Roslyn_Dynamic_Compiling.html
Copyright © 2011-2022 走看看