C#如何动态编译代码?附完整项目实例与源码

来源:网站建设作者:星宫一花头衔:网络博主
导读:本期聚焦于小伙伴创作的《C#如何动态编译代码?附完整项目实例与源码》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C#如何动态编译代码?附完整项目实例与源码》有用,将其分享出去将是对创作者最好的鼓励。

C#动态编译指的是在程序运行期间,将字符串形式的C#代码实时编译为可执行的程序集,并且可以直接调用编译后生成的方法或类型,这项技术能够极大提升程序的灵活性,支持动态扩展功能。

C#如何动态编译代码?附完整项目实例与源码

C#动态编译的两种主流实现方案

目前C#中实现动态编译主要有两种常用方式,分别是传统的CodeDom编译方案和微软推出的Roslyn编译方案,二者各有适用场景。

1. CodeDom编译方案

CodeDom是.NET Framework自带的代码生成与编译命名空间,不需要额外引入第三方依赖,适合旧版本.NET项目使用,但是功能相对有限,对C#新语法支持不足。

使用CodeDom实现动态编译的核心步骤如下:

  • 创建CSharpCodeProvider实例,用于提供C#代码编译能力
  • 配置编译参数,包括输出程序集路径、引用的程序集等
  • 调用CompileAssemblyFromSource方法执行编译
  • 从编译生成的程序集中获取类型并调用方法

下面是完整的CodeDom动态编译实例源码:

using System;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;

namespace DynamicCompileDemo
{
    class CodeDomCompileExample
    {
        static void Main(string[] args)
        {
            // 待编译的C#代码片段
            string code = @"
                using System;
                namespace DynamicNamespace
                {
                    public class DynamicClass
                    {
                        public int Add(int a, int b)
                        {
                            return a + b;
                        }
                        public void PrintHello()
                        {
                            Console.WriteLine(""动态编译的方法执行成功"");
                        }
                    }
                }";

            // 创建C#代码编译提供者
            using (CSharpCodeProvider provider = new CSharpCodeProvider())
            {
                // 配置编译参数
                CompilerParameters parameters = new CompilerParameters();
                // 添加引用的基础程序集
                parameters.ReferencedAssemblies.Add("System.dll");
                // 不生成可执行文件,生成动态程序集
                parameters.GenerateInMemory = true;
                // 不生成调试信息
                parameters.IncludeDebugInformation = false;

                // 执行编译
                CompilerResults result = provider.CompileAssemblyFromSource(parameters, code);

                // 检查编译是否有错误
                if (result.Errors.HasErrors)
                {
                    Console.WriteLine("编译失败,错误信息:");
                    foreach (CompilerError error in result.Errors)
                    {
                        Console.WriteLine($"行{error.Line}:{error.ErrorText}");
                    }
                    return;
                }

                // 获取编译后的程序集
                Assembly assembly = result.CompiledAssembly;
                // 获取动态生成的类型
                Type dynamicType = assembly.GetType("DynamicNamespace.DynamicClass");
                // 创建类型实例
                object instance = Activator.CreateInstance(dynamicType);
                // 获取Add方法并执行
                MethodInfo addMethod = dynamicType.GetMethod("Add");
                object addResult = addMethod.Invoke(instance, new object[] { 10, 20 });
                Console.WriteLine($"Add方法执行结果:{addResult}");
                // 获取PrintHello方法并执行
                MethodInfo printMethod = dynamicType.GetMethod("PrintHello");
                printMethod.Invoke(instance, null);
            }
        }
    }
}

2. Roslyn编译方案

Roslyn是微软推出的新一代.NET编译器平台,支持C#全量语法,编译速度更快,还能提供丰富的语法分析能力,适合.NET Core及以上版本的项目,需要额外引入NuGet包Microsoft.CodeAnalysis.CSharp

使用Roslyn实现动态编译的核心步骤如下:

  • 引入Roslyn相关NuGet包
  • 创建语法树,解析输入的C#代码片段
  • 配置编译选项,添加引用的元数据引用
  • 调用编译方法生成程序集
  • 加载程序集并调用目标方法

下面是完整的Roslyn动态编译实例源码:

using System;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;

namespace DynamicCompileDemo
{
    class RoslynCompileExample
    {
        static void Main(string[] args)
        {
            // 待编译的C#代码片段
            string code = @"
                using System;
                namespace DynamicNamespace
                {
                    public class DynamicClass
                    {
                        public int Multiply(int a, int b)
                        {
                            return a * b;
                        }
                        public string GetCurrentTime()
                        {
                            return DateTime.Now.ToString(""yyyy-MM-dd HH:mm:ss"");
                        }
                    }
                }";

            // 解析C#代码生成语法树
            SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);

            // 获取引用的核心程序集元数据
            string coreLibPath = typeof(object).GetTypeInfo().Assembly.Location;
            MetadataReference[] references = new MetadataReference[]
            {
                MetadataReference.CreateFromFile(coreLibPath)
            };

            // 创建编译对象
            CSharpCompilation compilation = CSharpCompilation.Create(
                "DynamicAssembly",
                syntaxTrees: new[] { syntaxTree },
                references: references,
                options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
            );

            // 将编译结果输出到内存流
            using (MemoryStream ms = new MemoryStream())
            {
                EmitResult result = compilation.Emit(ms);
                // 检查编译是否有错误
                if (!result.Success)
                {
                    Console.WriteLine("编译失败,错误信息:");
                    foreach (Diagnostic diagnostic in result.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error))
                    {
                        Console.WriteLine(diagnostic.GetMessage());
                    }
                    return;
                }

                // 重置内存流位置并加载程序集
                ms.Seek(0, SeekOrigin.Begin);
                Assembly assembly = Assembly.Load(ms.ToArray());
                // 获取动态生成的类型
                Type dynamicType = assembly.GetType("DynamicNamespace.DynamicClass");
                // 创建类型实例
                object instance = Activator.CreateInstance(dynamicType);
                // 获取Multiply方法并执行
                MethodInfo multiplyMethod = dynamicType.GetMethod("Multiply");
                object multiplyResult = multiplyMethod.Invoke(instance, new object[] { 5, 6 });
                Console.WriteLine($"Multiply方法执行结果:{multiplyResult}");
                // 获取GetCurrentTime方法并执行
                MethodInfo timeMethod = dynamicType.GetMethod("GetCurrentTime");
                object timeResult = timeMethod.Invoke(instance, null);
                Console.WriteLine($"当前时间:{timeResult}");
            }
        }
    }
}

两种动态编译方案的对比

为了帮助开发者选择合适的动态编译方案,下面从多个维度对两种方案进行对比:

对比维度CodeDom方案Roslyn方案
适用框架.NET Framework.NET Core、.NET 5+
新语法支持仅支持旧版C#语法支持全量C#新语法
额外依赖无,框架内置需要引入Roslyn NuGet包
编译性能较低较高
语法分析能力强,支持语法检查、补全

动态编译的注意事项

在实际项目中使用动态编译功能时,需要注意以下几点:

  • 安全问题:动态编译的代码如果来自外部输入,可能存在恶意代码注入风险,需要对输入代码做严格的校验和沙箱隔离
  • 性能问题:动态编译本身有一定的性能开销,频繁编译相同代码时建议增加缓存机制,避免重复编译
  • 异常处理:编译失败、方法调用失败的场景都需要做好异常捕获,避免程序崩溃
  • 程序集卸载:动态编译生成的程序集默认会加载到应用域中,无法单独卸载,如果需要频繁更新动态代码,建议使用独立的应用域实现卸载
动态编译是C#中非常实用的高级特性,合理运用可以解决很多场景下的灵活扩展需求,开发者可以根据项目的框架版本和功能需求选择合适的实现方案。

C#动态编译RoslynCodeDom编译原理修改时间:2026-06-18 09:12:42

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。