Files
serein-flow/Library/Utils/DynamicCompiler.cs

101 lines
3.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Library.Utils
{
/// <summary>
/// 动态编译
/// </summary>
public class DynamicCompiler
{
private readonly HashSet<MetadataReference> _references = new HashSet<MetadataReference>();
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(); // 生成随机程序集名称
}
CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName,
new[] { syntaxTree },
_references,
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
);
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);
return Assembly.Load(ms.ToArray());
}
}
}
}