C# 动态编译

news2025/4/17 21:18:56

一、简介

CSharpCodeProvider 是 .NET 提供的一个强大工具,它允许开发人员在应用程序运行时动态地生成和执行 C# 代码。这一特性为后端开发带来了前所未有的灵活性和动态性,特别是在处理那些需要高度定制化或难以在编译时确定逻辑的场景时,尤为有用。

基本概念

动态编译是指程序在运行时能够接收源代码,并将其编译成可执行代码的过程。与传统的静态编译相比,动态编译不需要提前将源代码编译成程序集,而是可以在程序运行时即时完成这一过程。CSharpCodeProvider 正是这一概念的实现者之一,它利用 System.CodeDom.Compiler 和 Microsoft.CSharp 命名空间中的类来完成这一任务。

主要优势

  1. 灵活性:使用 CSharpCodeProvider,开发人员可以根据运行时需求动态生成和执行代码,实现高度定制化的功能。这特别适用于需要根据用户输入或外部数据源动态生成代码的场景。
  2. 插件系统:CSharpCodeProvider 可以用于开发插件系统,允许用户在应用程序运行时动态添加、加载和执行插件。这极大地提高了应用程序的扩展性和可维护性。
  3. 执行速度:尽管动态编译涉及到运行时的编译过程,但一旦代码被编译成程序集,其执行速度将接近静态编译的代码。这是因为编译后的代码以程序集的形式存在,可以被 .NET 运行时高效执行。
  4. 脚本引擎:通过 CSharpCodeProvider,开发人员可以实现一个简单的脚本引擎,允许用户在运行时编写和执行脚本代码。这为需要快速原型开发或脚本自动化功能的应用程序提供了便利。

效果:

二、实现效果

在网上的许多案例中,就用字符串写了一个 Hello World 就完事了,但实际项目中,这种案例几乎没有什么意义,所以这里我直接编译一整个项目,即使如此,也只是 CSharpCodeProvider  所有功能中的凤毛麟角,也只能做参考,项目结构如下:

需要编译的项目就是 WindowsFormsApp1,这名字我用的默认名字,为了防止一些没用的 .cs 文件也编译到其中,我添加了黑名单文件夹和黑名单文件的功能

新建一个 Winform 项目,项目名:动态编译,这里只是演示,所以名字我起的比较随意

代码:

using Microsoft.CSharp;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace 动态编译
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 黑名单文件
        /// </summary>
        private List<string> BlacklistFiles = new List<string>();
        /// <summary>
        /// 黑名单文件夹
        /// </summary>
        private List<string> BlacklistFolders = new List<string>();

        private void Form1_Load(object sender, EventArgs e)
        {
            BlacklistFolders.Add("Properties");
            BlacklistFolders.Add("bin");
            BlacklistFolders.Add("obj");
            BlacklistFiles.Add("Program.cs");

            string startupPath = Application.StartupPath;
            string path = Path.GetFullPath(Path.Combine(startupPath, @"..\..\..\WindowsFormsApp1"));
            string mainFormName = "WindowsFormsApp1.Form1";
            CompileAndRunWinForm(path, mainFormName);
        }

        private void CompileAndRunWinForm(string sourceDirectory, string mainFormName)
        {
            var (sourceFiles, resourceFiles) = GetFiles(sourceDirectory);
            var codeProvider = new CSharpCodeProvider();
            var parameters = new CompilerParameters
            {
                GenerateExecutable = false,
                OutputAssembly = $"{Application.StartupPath}\\DynamicAssembly.dll",
                GenerateInMemory = false,
                TreatWarningsAsErrors = false
            };

            parameters.ReferencedAssemblies.Add("System.dll");
            parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
            parameters.ReferencedAssemblies.Add("System.Drawing.dll");
            parameters.ReferencedAssemblies.Add("System.Core.dll");
            parameters.ReferencedAssemblies.Add("System.Data.dll");

            foreach (var resx in resourceFiles)
            {
                parameters.EmbeddedResources.Add(resx);
            }

            var results = codeProvider.CompileAssemblyFromFile(parameters, sourceFiles.ToArray());
            if (results.Errors.HasErrors)
            {
                foreach (CompilerError error in results.Errors)
                {
                    Console.WriteLine($"Error {error.ErrorNumber}: {error.ErrorText}");
                }
                return;
            }

            Console.WriteLine($"编译DLL路径: {results.PathToAssembly}");
            if (string.IsNullOrEmpty(results.PathToAssembly))
            {
                Console.WriteLine("编译DLL路径为空");
                return;
            }

            Assembly assembly = Assembly.LoadFile(results.PathToAssembly);
            Type mainFormType = assembly.GetType(mainFormName);
            if (mainFormType == null)
            {
                Console.WriteLine("未找到 {0} 对应的 Type", mainFormType);
                return;
            }

            Form mainForm = (Form)Activator.CreateInstance(mainFormType);
            mainForm.Show();
        }

        private (List<string>, List<string>) GetFiles(string folderPath)
        {
            List<string> csFiles = new List<string>();
            List<string> resxFiles = new List<string>();

            var allFiles = Directory.GetFiles(folderPath, "*.*", SearchOption.AllDirectories)
                                    .Where(file => file.EndsWith(".cs") || file.EndsWith(".resx"));

            foreach (var file in allFiles)
            {
                string fileDirectory = Path.GetDirectoryName(file);

                bool isInBlacklist = BlacklistFiles.Any(blacklistedFile =>
                    file.EndsWith(blacklistedFile, StringComparison.OrdinalIgnoreCase));
                bool isInBlacklistFolder = BlacklistFolders.Any(blacklistedFolder =>
                    fileDirectory.Split(Path.DirectorySeparatorChar).Contains(blacklistedFolder, StringComparer.OrdinalIgnoreCase));

                if (!isInBlacklist && !isInBlacklistFolder)
                {
                    if (file.EndsWith(".cs", StringComparison.OrdinalIgnoreCase))
                        csFiles.Add(file);
                    else if (file.EndsWith(".resx", StringComparison.OrdinalIgnoreCase))
                        resxFiles.Add(file);
                }
            }

            return (csFiles, resxFiles);
        }
    }
}

新建一个 Winform 项目,项目名: WindowsFormsApp1,这里只是演示,希望你不要将这种项目名用在工作中,默认的界面 Form1 界面如下:

代码:

using System;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Console.WriteLine("这是 button1 的点击事件");

            Form2 form2 = new Form2();
            form2.Show();
        }
    }
}

在按钮中,添加了显示 Form2 的代码,没有其他功能了

Form2 界面如下,没有任何代码

运行后,动态编译项目的 Debug 目录中就会多出一个编译的 DLL,如下:

源码:

https://download.csdn.net/download/qq_38693757/89771252

效果:

结束

如果这个帖子对你有所帮助,欢迎 关注 + 点赞 + 留言

end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2146570.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【项目实训1】手把手教你使用 Dehazeformer 模型去雾:服务器租用、环境配置、自定义数据集、模型的训练与测试(全网最全的操作指导)

前言 文章性质:实操笔记 📖 代码来源:GitHub - IDKiro/DehazeFormer: [IEEE TIP] Vision Transformers for Single Image Dehazing 主要内容:本文详细记录了如何借助 Tabby 图形界面工具在 AutoDL 远程服务器上配置 Dehazeformer 所需的项目环境,并且成功运行 Dehazeform…

HeterGCL-Graph Contrastive Learning Framework on Heterophilic Graph

推荐指数: #paper/⭐⭐ 发表于:IJCAI24 类型&#xff1a;个人觉得算是图结构学习&#xff0c;部分思想不错 问题背景&#xff1a; 传统的随机增强不适合异配图。随机增强主要保留的是同配信息。这就导致在异配图用随机增强会抑制高频信息&#xff0c;直接使用时不合理的(这个…

JDBC 编程

目录 JDBC 是什么 JDBC 的工作原理 JDBC 的使用 引入驱动 使用 常用接口和类 Connection Statement ResultSet 使用总结 JDBC 是什么 JDBC&#xff08;Java Database Connectivity&#xff09;&#xff1a;Java数据库连接&#xff0c;是一种用于执行 SQL 语句的Java…

【附激活码】2024最新PyCharm下载安装激活汉化教程!

一、PyCharm激活 激活码&#xff1a; KQ8KMJ77TY-eyJsaWNlbnNlSWQiOiJLUThLTUo3N1RZIiwibGljZW5zZWVOYW1lIjoiVW5pdmVyc2l0YXMgTmVnZXJpIE1hbGFuZyIsImxpY2Vuc2VlVHlwZSI6IkNMQVNTUk9PTSIsImFzc2lnbmVlTmFtZSI6IkpldOWFqOWutuahtiDorqTlh4blupflkI0iLCJhc3NpZ25lZUVtYWlsIjoi…

如何使用 Python Matplotlib 绘制 3D 曲面图

在数据可视化中&#xff0c;3D 图表是一个非常有用的工具&#xff0c;特别是当想要展示复杂的三维数据时&#xff0c;如期权的波动率曲面。Python 的 matplotlib 库提供了生成各种类型图表&#xff0c;包括 3D 图表。 本文将介绍如何使用 Python 中的 matplotlib 绘制 3D 曲面…

分公司=一部门——组合模式

文章目录 分公司一部门——组合模式分公司不就是一部门吗&#xff1f;组合模式透明方式与安全方式何时使用组合模式公司管理系统组合模式好处 分公司一部门——组合模式 分公司不就是一部门吗&#xff1f; 时间&#xff1a;5月10日19点  地点&#xff1a;小菜、大鸟住所的客…

开放的数据时代:Web3和个人隐私的未来

在数字化和信息化的时代&#xff0c;数据隐私成为了公众关注的焦点。随着Web3技术的兴起&#xff0c;个人隐私保护进入了一个新的阶段。Web3作为去中心化的互联网架构&#xff0c;提出了对数据控制和隐私保护的新方案。本文将探讨Web3如何影响个人隐私的未来&#xff0c;并分析…

[附源码]SpringBoot+VUE+Java实现人脸识别系统

今天带来一款优秀的项目&#xff1a;java人脸识别系统源码 。 系统采用的流行的前后端分离结构&#xff0c;内含功能包括 “人脸数数据录入”&#xff0c;“人脸管理”&#xff0c;“摄像头识别” 如果您有任何问题&#xff0c;也请联系小编&#xff0c;小编是经验丰富的程序员…

编写程序,在一行上显示1-5数字,每个相邻的数字要求用空格进行分开

目录 前言 一、一行输出&#xff08;使用一个System语句输出&#xff09; 二、多行输出&#xff08;使用多&#xff08;N&#xff09;个System语句输出&#xff09; 三、循环输出&#xff08;使用for语句循环在通过System语句输出&#xff09; 四、完整代码 前言 1.本文所…

只会Python编程,做量化交易策略用QMT怎么样?听说QMT是支持Python的!

QMT是专门为机构、活跃投资者、高净值客户等专业投资者研发的智能量化交易终端&#xff0c;拥有高速行情、极速交易、策略交易、多维度风控等专业功能&#xff0c;满足专业投资者的特殊交易需求。覆盖业务范围广:沪深A股、港股通、两融、期权、期货。 适合用QMT的投资者&#x…

使用 UWA Gears 定位游戏内存问题

UWA Gears 是UWA最新发布的无SDK性能分析工具。针对移动平台&#xff0c;提供了实时监测和截帧分析功能&#xff0c;帮助您精准定位性能热点&#xff0c;提升应用的整体表现。 内存不足、内存泄漏和过度使用等问题&#xff0c;常常导致游戏出现卡顿、崩溃&#xff0c;甚至影响…

偷偷告诉你,学会使用这几样测试用例管理工具就够啦!

在软件开发过程中&#xff0c;测试是必不可少的一环&#xff0c;而测试用例则是测试的重要依据。如何有效地管理测试用例&#xff0c;提高测试效率&#xff0c;是每一个测试人员都需要面对的问题。本文将为你介绍几款实用的测试用例管理工具&#xff0c;帮助你更好地进行测试工…

2024年双十一不容错过的好物分享,最值得买的五款单品

双十一购物狂欢节将至&#xff0c;这是一场属于“剁手党”的年度盛宴。每年的11月11日&#xff0c;各大电商平台纷纷推出海量优惠活动&#xff0c;吸引无数消费者积极参与。对于热衷于寻找好物的人来说&#xff0c;双十一无疑是一个不容错过的机会&#xff0c;双十一好物不间断…

基于JavaWeb开发的java+Springboot操作系统教学交流平台详细设计实现

基于JavaWeb开发的javaSpringboot操作系统教学交流平台详细设计实现 &#x1f345; 作者主页 网顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接…

零基础制作一个ST-LINK V2 附PCB文件原理图 AD格式

资料下载地址&#xff1a;零基础制作一个ST-LINK V2 附PCB文件原理图 AD格式 ST-LINK/V2是一款可以在线仿真以及下载STM8以及STM32的开发工具。支持所有带SWIM接口的STM8系列单片机;支持所有带JTAG / SWD接口的STM32系列单片机。 基本属性 ST-LINK/V2是ST意法半导体为评估、开…

【我的 PWN 学习手札】劫持 tcache_perthread_struct

目录 前言 一、tcache perthread struct 二、劫持 tcache_perthread_struct 三、测试与模板 前言 tcache 是 glibc 2.26 (ubuntu 17.10) 之后引入的一种技术&#xff0c;目的是提升堆管理的性能&#xff0c;与 fast bin 类似。 tcache 引入了两个新的结构体&#xff0c; tc…

idear导入他人项目如何快速运行

最近idear经常导入别人的项目&#xff0c;结果永远在加载依赖项。网上查了一堆资料&#xff0c;什么jdk问题&#xff0c;环境变量问题&#xff0c;maven仓库路径问题&#xff0c;总之就是没啥用。那有没有什么简单粗暴的办法&#xff0c;能够导入项目后快速运行呢。 解决方法&a…

独立站技能树之建站33项自检清单 1.0丨出海笔记

很多时候大家建好站之后很嗨&#xff0c;但过一会就开始担忧各种纠结我是不是还有什么点没做好&#xff0c;或者我的站漏了什么东西&#xff0c;那么接下来以下这个独立站自检清单能很好的帮到你。其实对于新手我还是建议大家直接用一些模板&#xff0c;因为模板上面基本该有的…

Gitee丝滑版本:成功在新电脑添加新文件

git 关键步骤 1.首先在新电脑建一个文件夹&#xff0c;然后打开这个文件夹里面右键打开OPEN BASH GIT HERE。 2.然后输入git init&#xff0c;会在文件夹生成一个git.文件&#xff0c;接着把复制的get clone命令克隆过去就可以下载了&#xff0c;如果遇到403问题&#xff0c…

【机器学习】从数据到决策——完整的机器学习项目实战解析

【机器学习】从数据到决策——完整的机器学习项目实战解析 1. 引言 机器学习项目不仅仅是训练一个模型&#xff0c;它涉及从数据预处理到模型评估的完整流程。本文将通过一个完整的机器学习项目&#xff0c;展示从数据准备到最终决策的关键步骤。这将帮助你理解如何系统地构建…