首页 > 其他分享 >使用 Roslyn引擎动态编译代码

使用 Roslyn引擎动态编译代码

时间:2023-08-07 09:14:20浏览次数:40  
标签:Assembly diagnostic 编译 引擎 result ms Roslyn new

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;
}

标签:Assembly,diagnostic,编译,引擎,result,ms,Roslyn,new
From: https://www.cnblogs.com/weifeng123/p/17610560.html

相关文章

  • linux基础:编译
    程序编译在linux中,gnu项目提供了gcc编译器、g++编译器和gdb调试器。C和C++语言正在不断发展,为了保持兼容程序语言的最新特性,开发者通常选择GCC来编译C语言编写的源代码,选择G++来编译C++语言编写的源代码。编译过程:预处理、编译、汇编、链接预处理:将所有的#include头文件、#......
  • bazel test 编译失败:googletest、gtest 报错
    问题描述bazeltest遇到很多奇怪的编译错误,报错位置位于“googletest”目录,而且没有修改过googletest源码:ERROR:/bazel_cache/output_user_root/.../external/google/BUILD.bazel:80:11:Compilinggoogletest/src/gtest-matchers.ccfailed:(Exit1):gccfailed:errore......
  • clang 静态编译 ffmpeg
    文档说明:只记录关键的地方;发文时间:2023-08-06意义:静态编译ffmpeg,可自由裁剪,使用libc构建;支持macos、linux构建;生成库依赖库图环境:alpine:3.17dockerclang备注:大部分软件源代码来源于github.com,下载过程断断续续的。请自备代理借助swoole-cli已经编写好......
  • 一、Flink-1.13.6源码编译运行
    1、概述本节演示如何在本地编译、运行Flink源码。技术有限,欢迎各位大佬在评论区批评指正。2、版本说明名称版本flink1.13.6jdk1.8Maven3.2.5操作系统Mac3、编译Flink源码1)从github下载Flink源码gitclonehttps://github.com/apache/flink......
  • 深度学习编译器前端技术概述
    AI编译器在前端经常会做一些静态分析,方便在前端做一些优化:自动微分等。中间表示(IntermediateRepresentation,IR)IR是编译器用于表示源代码的数据结构或代码,是程序编译过程中介于源语言和目标语言之间的程序表示。几乎所有的编译器都需要某种形式的中间表示,来对被分析、转换......
  • 多个C文件混合编译,涉及函数相互调用,地址传递要注意的!
    tc.h#pragmaoncechar*fun();//main函数调用到这个函数,但是在其他.c中定义,在头文件申明下先tacc.c#include<stdio.h>char*fun(){printf("saDHAKJHFJ\n");inti=100;printf("i=%d\n",i);char*pr=(char*)malloc(100);*pr......
  • 传奇引擎知识分享HxM2幻想引擎简单介绍与假人功能设置
    HxM2幻想游戏开发引擎又被传奇GM们称为HX引擎,也叫幻想引擎,相对于现在流行的传奇版本中,幻想HX是一个低产的引擎,现在已经非常小众化了,可能由于年代久远,款引擎现在使用的很少,但是也出过非常火爆的版本,比如灵域迷失系列、恶魔大极品等等……HXM幻想引擎也现在仍在更新,而且一直有保持免......
  • 传奇引擎知识分享传奇GEE引擎设置装备物品绑定的方法
    功能:设置新的装备绑定功能.(专用登录器)SetItemBind,设置物品和人物绑定绑定后物品属性会显示“已绑定”格式:SetItemBind装备位置(-1~13,-1时为OK框中物品)绑定(0-1)说明:参数20=取消1=绑定例子:绑定武器.#IFCheckGold10000#ACTSetItemBind11Take金币10000例子:取消......
  • openGauss的SQL引擎在3.1.0版本中做了哪些优化?
    openGauss的SQL引擎在3.1.0版本中做了哪些优化?收录于合集#技术干货83个查询执行能力对数据库来说至关重要,这直接决定了查询语句生成的执行计划以何种方式进行执行,如果哪个执行算子的执行表现不好,将会对数据库的整体性能产生极大的影响。同时,执行算子的实现也极大考验一款数据库的工......
  • 传奇架设技术传奇引擎BLUEM2引擎中任意魔法接口设置方法
    功能:任意魔法接口.不再限制为几个简单的魔法了.使用此引擎的朋友也可以Diy魔法了示例:目标触发为[@MagTagFuncXXX].当前人物触发为[@MagSelfFuncXXX].XXX为魔法ID.建议做大点.不要太接近现有的魔法ID.;新增魔法ID为248的魔法.鼠标有目标时则触发QFunction-0.txt中的[@MagTagFunc248]......