mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
121 lines
3.8 KiB
C#
121 lines
3.8 KiB
C#
using Microsoft.CodeAnalysis;
|
||
using Microsoft.CodeAnalysis.CSharp;
|
||
using Microsoft.CodeAnalysis.Emit;
|
||
using System.Reflection;
|
||
|
||
namespace Serein.NodeFlow.Tool
|
||
{
|
||
/// <summary>
|
||
/// 动态编译
|
||
/// </summary>
|
||
public class DynamicCompiler
|
||
{
|
||
private readonly HashSet<MetadataReference> _references = new HashSet<MetadataReference>();
|
||
|
||
/// <summary>
|
||
/// 构造一个新的动态编译器实例。
|
||
/// </summary>
|
||
public DynamicCompiler()
|
||
{
|
||
// 默认添加当前 AppDomain 加载的所有程序集
|
||
var defaultReferences = AppDomain.CurrentDomain.GetAssemblies()
|
||
.Where(a => !string.IsNullOrEmpty(a.Location)) // a.IsDynamic 动态程序集
|
||
.Select(a => MetadataReference.CreateFromFile(a.Location));
|
||
|
||
|
||
//AddReference(this.GetType());
|
||
_references.UnionWith(defaultReferences);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加依赖程序集(通过类型)
|
||
/// </summary>
|
||
/// <param name="type">类型所在的程序集</param>
|
||
public void AddReference(Type type)
|
||
{
|
||
var assemblyLocation = type.Assembly.Location;
|
||
if (!string.IsNullOrEmpty(assemblyLocation))
|
||
{
|
||
_references.Add(MetadataReference.CreateFromFile(assemblyLocation));
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加依赖程序集(通过文件路径)
|
||
/// </summary>
|
||
/// <param name="assemblyPath">程序集文件路径</param>
|
||
public void AddReference(string assemblyPath)
|
||
{
|
||
if (File.Exists(assemblyPath))
|
||
{
|
||
_references.Add(MetadataReference.CreateFromFile(assemblyPath));
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 编译 C# 代码并返回程序集
|
||
/// </summary>
|
||
/// <param name="code">C# 代码文本</param>
|
||
/// <param name="assemblyName">程序集名称(可选)</param>
|
||
/// <returns>成功返回 Assembly,失败返回 null</returns>
|
||
public Assembly Compile(string code, string assemblyName = null)
|
||
{
|
||
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);
|
||
if (assemblyName is null)
|
||
{
|
||
assemblyName = Path.GetRandomFileName(); // 生成随机程序集名称
|
||
|
||
}
|
||
|
||
var temp_dir = Path.Combine(Directory.GetCurrentDirectory(), "temp");
|
||
if (!Directory.Exists(temp_dir))
|
||
{
|
||
Directory.CreateDirectory(temp_dir);
|
||
}
|
||
var savePath = Path.Combine(temp_dir, $"{assemblyName}.dll");
|
||
|
||
var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
|
||
|
||
|
||
CSharpCompilation compilation = CSharpCompilation.Create(
|
||
assemblyName,
|
||
new[] { syntaxTree },
|
||
_references,
|
||
options
|
||
|
||
);
|
||
|
||
using (var ms = new MemoryStream())
|
||
{
|
||
EmitResult result = compilation.Emit(ms);
|
||
|
||
if (!result.Success)
|
||
{
|
||
Console.WriteLine("编译失败:");
|
||
foreach (var diagnostic in result.Diagnostics)
|
||
{
|
||
Console.WriteLine(diagnostic.ToString());
|
||
}
|
||
return null;
|
||
}
|
||
|
||
ms.Seek(0, SeekOrigin.Begin);
|
||
var t12 = AppContext.BaseDirectory;
|
||
var assembly = Assembly.Load(ms.ToArray());
|
||
var t1 = assembly.Location;
|
||
var t = assembly.GetType().Assembly.Location;
|
||
|
||
// 保存
|
||
|
||
compilation.Emit(savePath);
|
||
return assembly;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
}
|
||
}
|