重新设计了项目的保存文件结构

This commit is contained in:
fengjiayi
2025-03-18 11:52:54 +08:00
parent 1db8a44135
commit fffb22b3a8
24 changed files with 831 additions and 109 deletions

View File

@@ -0,0 +1,127 @@
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.NodeFlow.Tool
{
/// <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(); // 生成随机程序集名称
}
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 assembly = Assembly.Load(ms.ToArray());
var t1 = assembly.Location;
var t = assembly.GetType().Assembly.Location;
// 保存
compilation.Emit(savePath);
return assembly;
}
}
public void Save()
{
}
}
}

View File

@@ -26,19 +26,33 @@ namespace Serein.NodeFlow
/// </summary>
public class FlowLibrary
{
private readonly Assembly assembly;
private readonly Action actionOfUnloadAssmbly;
private readonly Assembly _assembly;
public FlowLibrary(Assembly assembly,
Action actionOfUnloadAssmbly)
//private readonly Action actionOfUnloadAssmbly;
/*, Action actionOfUnloadAssmbly*/
//this.actionOfUnloadAssmbly = actionOfUnloadAssmbly;
public FlowLibrary(Assembly assembly)
{
this.assembly = assembly;
this.actionOfUnloadAssmbly = actionOfUnloadAssmbly;
this._assembly = assembly;
this.FullName = Path.GetFileName(_assembly.Location);
this.FilePath = _assembly.Location;
}
public string FullName => assembly.GetName().FullName;
public FlowLibrary(Assembly assembly,
string filePath)
{
this._assembly = assembly;
this.FullName = Path.GetFileName(filePath); ;
this.FilePath = filePath;
}
public string Version => assembly.GetName().Version.ToString();
public string FullName { get; private set; }
public string FilePath { get; private set; }
/// <summary>
/// 加载程序集时创建的方法描述
@@ -68,7 +82,7 @@ namespace Serein.NodeFlow
DelegateDetailss.Clear();
RegisterTypes.Clear();
MethodDetailss.Clear();
actionOfUnloadAssmbly?.Invoke();
//actionOfUnloadAssmbly?.Invoke();
}
@@ -78,11 +92,12 @@ namespace Serein.NodeFlow
/// <returns></returns>
public NodeLibraryInfo ToInfo()
{
var assemblyName = _assembly.GetName().Name;
return new NodeLibraryInfo
{
AssemblyName = assembly.GetName().Name,
FileName = Path.GetFileName(assembly.Location),
FilePath = assembly.Location,
AssemblyName = assemblyName,
FileName = this.FullName,
FilePath = this.FilePath,
};
@@ -94,8 +109,9 @@ namespace Serein.NodeFlow
/// </summary>
/// <param name="assembly">程序集本身</param>
/// <returns></returns>
public bool LoadAssembly(Assembly assembly)
public bool LoadAssembly()
{
Assembly assembly = this._assembly;
#region
// 加载DLL创建 MethodDetails、实例作用对象、委托方法

View File

@@ -39,7 +39,36 @@ namespace Serein.NodeFlow.Tool
/// <returns></returns>
public (NodeLibraryInfo, List<MethodDetailsInfo>) LoadLibraryOfPath(string libraryfilePath)
{
return LoadDllNodeInfo(libraryfilePath);
var dir = Path.GetDirectoryName(libraryfilePath); // 获取目录路径
var sereinFlowBaseLibraryPath = Path.Combine(dir, SereinBaseLibrary);// 每个类库下面至少需要有“Serein.Library.dll”类库依赖
if (!Path.Exists(sereinFlowBaseLibraryPath))
{
throw new Exception($"从文件加载DLL失败目标文件夹不存在{SereinBaseLibrary}文件" );
}
var flowAlc = new FlowLibraryAssemblyContext(sereinFlowBaseLibraryPath, Path.GetFileName(libraryfilePath));
var assembly = flowAlc.LoadFromAssemblyPath(libraryfilePath); // 加载指定路径的程序集
var reulst = LoadDllNodeInfo(assembly);
if(reulst.Item1 is null || reulst.Item2.Count == 0)
{
flowAlc?.Unload(); // 卸载程序集
flowAlc = null;
GC.Collect(); // 强制触发GC确保卸载成功
GC.WaitForPendingFinalizers();
throw new Exception("从文件加载DLL失败"+ libraryfilePath);
}
return reulst;
}
/// <summary>
/// 加载类库
/// </summary>
/// <param name="assembly"></param>
/// <returns></returns>
public (NodeLibraryInfo, List<MethodDetailsInfo>) LoadLibraryOfPath(Assembly assembly)
{
return LoadDllNodeInfo(assembly);
}
/// <summary>
@@ -206,84 +235,44 @@ namespace Serein.NodeFlow.Tool
/// </summary>
public readonly static string SereinBaseLibrary = $"{nameof(Serein)}.{nameof(Serein.Library)}.dll";
private (NodeLibraryInfo, List<MethodDetailsInfo>) LoadDllNodeInfo(string dllFilePath)
private (NodeLibraryInfo, List<MethodDetailsInfo>) LoadDllNodeInfo(Assembly assembly)
{
var fileName = Path.GetFileName(dllFilePath); // 获取文件名
if (SereinBaseLibrary.Equals(fileName))
if (assembly.FullName?.ToString().Equals(typeof(IFlowEnvironment).Assembly.FullName?.ToString()) == true)
{
return LoadAssembly(typeof(IFlowEnvironment).Assembly, () => {
//SereinEnv.PrintInfo(InfoType.WRAN, "基础模块不能卸载");
});
// 加载基础依赖
return LoadAssembly(typeof(IFlowEnvironment).Assembly);
}
else
{
var dir = Path.GetDirectoryName(dllFilePath); // 获取目录路径
var sereinFlowBaseLibraryPath = Path.Combine(dir, SereinBaseLibrary);
// 每个类库下面至少需要有“Serein.Library.dll”类库依赖
//AssemblyLoader assemblyLoader = new AssemblyLoader(dllFilePath);
var flowAlc = new FlowLibraryAssemblyContext(sereinFlowBaseLibraryPath, fileName);
Action actionUnload = () =>
try
{
flowAlc?.Unload(); // 卸载程序集
flowAlc = null;
GC.Collect(); // 强制触发GC确保卸载成功
GC.WaitForPendingFinalizers();
};
var assembly = flowAlc.LoadFromAssemblyPath(dllFilePath); // 加载指定路径的程序集
var assembly_result = LoadAssembly(assembly, actionUnload);
return assembly_result;
var assembly_result = LoadAssembly(assembly);
return assembly_result;
}
catch (Exception)
{
return (null,[]);
}
}
/* var dir = Path.GetDirectoryName(dllFilePath); // 获取目录路径
var sereinFlowLibraryPath = Path.Combine(dir, SereinLibraryDll);
// 每个类库下面至少需要有“Serein.Library.dll”类库依赖
var flowAlc = new FlowLibraryAssemblyContext(sereinFlowLibraryPath, fileName);
Action actionUnload = () =>
{
flowAlc?.Unload(); // 卸载程序集
flowAlc = null;
GC.Collect(); // 强制触发GC确保卸载成功
GC.WaitForPendingFinalizers();
};
var assembly = flowAlc.LoadFromAssemblyPath(dllFilePath); // 加载指定路径的程序集
if (_myFlowLibrarys.ContainsKey(assembly.GetName().Name))
{
actionUnload.Invoke();
throw new Exception($"程序集[{assembly.GetName().FullName}]已经加载过!");
}
FlowLibrary flowLibrary = new FlowLibrary(assembly, actionUnload);
if (flowLibrary.LoadAssembly(assembly))
{
_myFlowLibrarys.TryAdd(assembly.GetName().Name, flowLibrary);
(NodeLibraryInfo, List<MethodDetailsInfo>) result = (flowLibrary.ToInfo(),
flowLibrary.MethodDetailss.Values.Select(md => md.ToInfo()).ToList());
return result;
}
else
{
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败");
}*/
}
private (NodeLibraryInfo, List<MethodDetailsInfo>) LoadAssembly(Assembly assembly,Action actionUnload)
private (NodeLibraryInfo, List<MethodDetailsInfo>) LoadAssembly(Assembly assembly)
{
if (_myFlowLibrarys.ContainsKey(assembly.GetName().Name))
{
actionUnload.Invoke();
throw new Exception($"程序集[{assembly.GetName().FullName}]已经加载过!");
}
FlowLibrary flowLibrary = new FlowLibrary(assembly, actionUnload);
var loadResult = flowLibrary.LoadAssembly(assembly); // 加载程序集
FlowLibrary flowLibrary = new FlowLibrary(assembly);
var loadResult = flowLibrary.LoadAssembly(); // 加载程序集
if (loadResult)
{
var assemblyName = assembly.GetName().Name;
if (string.IsNullOrEmpty(assemblyName))
{
actionUnload.Invoke();
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败,没有程序集名称");
}
_myFlowLibrarys.TryAdd(assemblyName, flowLibrary);
@@ -296,7 +285,6 @@ namespace Serein.NodeFlow.Tool
}
else
{
actionUnload.Invoke();
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败");
}
}

View File

@@ -19,7 +19,7 @@ public static class NodeMethodDetailsHelper
/// </summary>
public static IEnumerable<MethodInfo> GetMethodsToProcess(Type type)
{
return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
.Where(m => m.GetCustomAttribute<NodeActionAttribute>()?.Scan == true);
}