C#实现在程序中动态编译一段C#代码并执行

该文章已生成可运行项目,

C# 可以通过 Roslyn 编译器 或 CSharpCodeProvider 实现动态编译并执行 C# 代码。以下是两种方法的详细介绍和示例代码。


方法 1:使用 CSharpCodeProvider(适用于 .NET Framework 和部分 .NET Core 版本)

CSharpCodeProvider 是 .NET 提供的一个类,用于动态编译和执行 C# 代码。它适用于 .NET Framework 和部分 .NET Core 版本。

示例代码

csharp

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

class Program
{
    static void Main()
    {
        // 定义要编译的 C# 代码
        string code = @"
            using System;
            public class DynamicClass
            {
                public void HelloWorld()
                {
                    Console.WriteLine(""Hello, World!"");
                }
            }";

        // 创建 CSharpCodeProvider 实例
        using (CSharpCodeProvider provider = new CSharpCodeProvider())
        {
            // 设置编译参数
            CompilerParameters parameters = new CompilerParameters
            {
                GenerateInMemory = true, // 在内存中生成程序集
                GenerateExecutable = false // 不生成可执行文件
            };

            // 添加引用的程序集
            parameters.ReferencedAssemblies.Add("System.dll");

            // 编译代码
            CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);

            // 检查编译错误
            if (results.Errors.HasErrors)
            {
                foreach (CompilerError error in results.Errors)
                {
                    Console.WriteLine($"Error: {error.ErrorText}");
                }
                return;
            }

            // 获取编译后的程序集
            Assembly assembly = results.CompiledAssembly;

            // 获取动态类型
            Type dynamicType = assembly.GetType("DynamicClass");

            // 创建动态类型的实例
            object dynamicInstance = Activator.CreateInstance(dynamicType);

            // 调用方法
            MethodInfo method = dynamicType.GetMethod("HelloWorld");
            method.Invoke(dynamicInstance, null);
        }
    }
}
代码解析
  1. CSharpCodeProvider:用于编译 C# 代码。

  2. CompilerParameters:设置编译参数,如是否在内存中生成程序集。

  3. CompileAssemblyFromSource:将源代码编译为程序集。

  4. Assembly 和反射:通过反射获取编译后的类型并调用方法。


方法 2:使用 Roslyn 编译器(适用于 .NET Core 和 .NET 5+)

Roslyn 是 .NET 的现代编译器平台,支持动态编译和执行 C# 代码。它比 CSharpCodeProvider 更强大且灵活。

示例代码

首先,安装 Roslyn 的 NuGet 包:

bash

dotnet add package Microsoft.CodeAnalysis.CSharp

然后编写代码:

csharp

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

class Program
{
    static void Main()
    {
        // 定义要编译的 C# 代码
        string code = @"
            using System;
            public class DynamicClass
            {
                public void HelloWorld()
                {
                    Console.WriteLine(""Hello, World!"");
                }
            }";

        // 创建语法树
        SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);

        // 引用必要的程序集
        var references = AppDomain.CurrentDomain.GetAssemblies()
            .Where(a => !a.IsDynamic)
            .Select(a => MetadataReference.CreateFromFile(a.Location))
            .Cast<MetadataReference>()
            .ToList();

        // 创建编译选项
        CSharpCompilationOptions options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);

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

        // 编译代码
        using (var ms = new System.IO.MemoryStream())
        {
            EmitResult result = compilation.Emit(ms);

            // 检查编译错误
            if (!result.Success)
            {
                foreach (var diagnostic in result.Diagnostics)
                {
                    Console.WriteLine(diagnostic.ToString());
                }
                return;
            }

            // 加载编译后的程序集
            ms.Seek(0, System.IO.SeekOrigin.Begin);
            Assembly assembly = Assembly.Load(ms.ToArray());

            // 获取动态类型
            Type dynamicType = assembly.GetType("DynamicClass");

            // 创建动态类型的实例
            object dynamicInstance = Activator.CreateInstance(dynamicType);

            // 调用方法
            MethodInfo method = dynamicType.GetMethod("HelloWorld");
            method.Invoke(dynamicInstance, null);
        }
    }
}
代码解析
  1. CSharpSyntaxTree.ParseText:将代码解析为语法树。

  2. MetadataReference:引用必要的程序集(如 System.Runtime)。

  3. CSharpCompilation:创建编译对象并设置编译选项。

  4. Emit:将代码编译为内存中的程序集。

  5. Assembly.Load:加载编译后的程序集并通过反射调用方法。


方法对比

特性CSharpCodeProviderRoslyn 编译器
支持平台.NET Framework 和部分 .NET Core.NET Core 和 .NET 5+
灵活性较低
性能较低
依赖项内置需要安装 NuGet 包
适用场景简单的动态编译需求复杂的动态编译需求

注意事项

  1. 安全性:动态编译和执行代码可能存在安全风险,需确保代码来源可信。

  2. 性能开销:动态编译会消耗一定的时间和资源,适合低频使用的场景。

  3. 依赖管理:动态代码可能需要引用额外的程序集,需确保依赖项可用。


通过以上方法,你可以在 C# 程序中动态编译并执行代码,适用于插件系统、脚本引擎等场景。

本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yuanpan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值