using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using System.Reflection;
namespace Serein.NodeFlow.Tool
{
///
/// 动态编译
///
public class DynamicCompiler
{
private readonly HashSet _references = new HashSet();
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);
}
///
/// 添加依赖程序集(通过类型)
///
/// 类型所在的程序集
public void AddReference(Type type)
{
var assemblyLocation = type.Assembly.Location;
if (!string.IsNullOrEmpty(assemblyLocation))
{
_references.Add(MetadataReference.CreateFromFile(assemblyLocation));
}
}
///
/// 添加依赖程序集(通过文件路径)
///
/// 程序集文件路径
public void AddReference(string assemblyPath)
{
if (File.Exists(assemblyPath))
{
_references.Add(MetadataReference.CreateFromFile(assemblyPath));
}
}
///
/// 编译 C# 代码并返回程序集
///
/// C# 代码文本
/// 程序集名称(可选)
/// 成功返回 Assembly,失败返回 null
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;
}
}
public void Save()
{
}
}
}