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);
}
}
}
代码解析
-
CSharpCodeProvider:用于编译 C# 代码。 -
CompilerParameters:设置编译参数,如是否在内存中生成程序集。 -
CompileAssemblyFromSource:将源代码编译为程序集。 -
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);
}
}
}
代码解析
-
CSharpSyntaxTree.ParseText:将代码解析为语法树。 -
MetadataReference:引用必要的程序集(如System.Runtime)。 -
CSharpCompilation:创建编译对象并设置编译选项。 -
Emit:将代码编译为内存中的程序集。 -
Assembly.Load:加载编译后的程序集并通过反射调用方法。
方法对比
| 特性 | CSharpCodeProvider | Roslyn 编译器 |
|---|---|---|
| 支持平台 | .NET Framework 和部分 .NET Core | .NET Core 和 .NET 5+ |
| 灵活性 | 较低 | 高 |
| 性能 | 较低 | 高 |
| 依赖项 | 内置 | 需要安装 NuGet 包 |
| 适用场景 | 简单的动态编译需求 | 复杂的动态编译需求 |
注意事项
-
安全性:动态编译和执行代码可能存在安全风险,需确保代码来源可信。
-
性能开销:动态编译会消耗一定的时间和资源,适合低频使用的场景。
-
依赖管理:动态代码可能需要引用额外的程序集,需确保依赖项可用。
通过以上方法,你可以在 C# 程序中动态编译并执行代码,适用于插件系统、脚本引擎等场景。

627

被折叠的 条评论
为什么被折叠?



