From e4972c62f292132cc6c7bcadaf23bef9b35b85a7 Mon Sep 17 00:00:00 2001 From: fengjiayi <12821976+ning_xi@user.noreply.gitee.com> Date: Sun, 3 Nov 2024 21:17:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E5=86=99=E4=BA=86=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E7=AE=A1=E7=90=86=EF=BC=8C=E5=B0=81=E8=A3=85?= =?UTF-8?q?=E4=B8=BA=E4=B8=80=E4=B8=AA=E5=B7=A5=E5=85=B7=E7=B1=BB=EF=BC=8C?= =?UTF-8?q?=E5=B0=86=E6=9D=A5=E8=AE=A1=E5=88=92=E5=AE=9E=E7=8E=B0=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E5=A2=9E=E5=8A=A0=E5=8D=B8=E8=BD=BD/=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E7=B1=BB=E5=BA=93=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Library/Api/IFlowEnvironment.cs | 8 +- Library/Entity/NodeLibraryInfo.cs | 108 ---------- Library/FlowNode/MethodDetails.cs | 14 +- Library/FlowNode/NodeModelBaseFunc.cs | 3 +- Library/FlowNode/SereinProjectData.cs | 43 +++- NodeFlow/Env/FlowEnvironment.cs | 203 ++++++++--------- NodeFlow/Env/FlowEnvironmentDecorator.cs | 8 +- NodeFlow/Env/FlowFunc.cs | 6 +- NodeFlow/Env/RemoteFlowEnvironment.cs | 5 +- NodeFlow/FlowStarter.cs | 6 +- NodeFlow/Model/CompositeConditionNode.cs | 3 +- NodeFlow/Model/SingleFlipflopNode.cs | 2 +- NodeFlow/Tool/FlowLibrary.cs | 230 ++++++++++++++++++++ NodeFlow/Tool/FlowLibraryLoader.cs | 61 ------ NodeFlow/Tool/FlowLibraryManagement.cs | 264 +++++++++++++++++++++++ NodeFlow/Tool/NodeMethodDetailsHelper.cs | 71 +++--- WorkBench/MainWindow.xaml.cs | 2 +- 17 files changed, 700 insertions(+), 337 deletions(-) delete mode 100644 Library/Entity/NodeLibraryInfo.cs create mode 100644 NodeFlow/Tool/FlowLibrary.cs delete mode 100644 NodeFlow/Tool/FlowLibraryLoader.cs create mode 100644 NodeFlow/Tool/FlowLibraryManagement.cs diff --git a/Library/Api/IFlowEnvironment.cs b/Library/Api/IFlowEnvironment.cs index 41ef41e..78b9319 100644 --- a/Library/Api/IFlowEnvironment.cs +++ b/Library/Api/IFlowEnvironment.cs @@ -676,8 +676,8 @@ namespace Serein.Library.Api /// /// 移除DLL /// - /// 程序集的名称 - bool RemoteDll(string assemblyName); + /// 程序集的名称 + bool RemoteDll(string assemblyFullName); /// /// 清理加载的DLL(待更改) @@ -860,7 +860,7 @@ namespace Serein.Library.Api /// 方法描述 /// 方法信息 /// - bool TryGetMethodDetailsInfo(string methodName, out MethodDetailsInfo mdInfo); + bool TryGetMethodDetailsInfo(string libraryName, string methodName, out MethodDetailsInfo mdInfo); /// /// 获取指定方法的Emit委托 @@ -868,7 +868,7 @@ namespace Serein.Library.Api /// /// /// - bool TryGetDelegateDetails(string methodName, out DelegateDetails del); + bool TryGetDelegateDetails(string libraryName, string methodName, out DelegateDetails del); #region 远程相关 diff --git a/Library/Entity/NodeLibraryInfo.cs b/Library/Entity/NodeLibraryInfo.cs deleted file mode 100644 index 801dac8..0000000 --- a/Library/Entity/NodeLibraryInfo.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Reflection; -using System.Text; - -namespace Serein.Library -{ - /// - /// 节点DLL依赖类,如果一个项目中引入了多个DLL,需要放置在同一个文件夹中 - /// - public class NodeLibraryInfo - { - /// - /// 文件名 - /// - public string FileName { get; set; } - - /// - /// 路径 - /// - public string FilePath { get; set; } - - /// - /// 所属的程序集名称 - /// - public string AssemblyName{ get; set; } - } - - - - /// - /// - /// - public class FlowLibrary - { - public FlowLibrary(string assemblyName, - Action actionOfUnloadAssmbly) - { - this.AssemblyName = assemblyName; - this.actionOfUnloadAssmbly = actionOfUnloadAssmbly; - } - - public string AssemblyName { get; } - - //public string AssemblyVersion { get; } - - /// - /// 加载程序集时创建的方法描述 - /// - public ConcurrentDictionary MethodDetailss { get; } = new ConcurrentDictionary(); - - /// - /// 管理通过Emit动态构建的委托 - /// - public ConcurrentDictionary DelegateDetailss { get; } = new ConcurrentDictionary(); - - /// - /// 记录不同的注册时机需要自动创建全局唯一实例的类型信息 - /// - public ConcurrentDictionary RegisterTypes { get; } = new ConcurrentDictionary(); - - - private readonly Action actionOfUnloadAssmbly; - - /// - /// 卸载当前程序集以及附带的所有信息 - /// - public void Upload() - { - actionOfUnloadAssmbly?.Invoke(); - } - - - /// - /// 通过方法名称获取对应的Emit委托(元数据),用于动态调用节点对应的方法 - /// - /// 方法名称 - /// Emit委托 - /// - public bool GetDelegateDetails(string methodName, out DelegateDetails dd) - { - return DelegateDetailss.TryGetValue(methodName, out dd); - } - - /// - /// 通过方法名称获取对应的方法描述(元数据),用于创建节点时,节点实例需要的方法描述 - /// - /// 方法名称 - /// 方法描述 - /// - public bool GetMethodDetails(string methodName, out MethodDetails md) - { - return MethodDetailss.TryGetValue(methodName, out md); - } - - public NodeLibraryInfo ToInfo() - { - return new NodeLibraryInfo - { - - } - } - - } - -} diff --git a/Library/FlowNode/MethodDetails.cs b/Library/FlowNode/MethodDetails.cs index f9632bc..d8489e5 100644 --- a/Library/FlowNode/MethodDetails.cs +++ b/Library/FlowNode/MethodDetails.cs @@ -2,6 +2,7 @@ using Serein.Library.Utils; using System; using System.Linq; +using System.Reflection; using System.Text; namespace Serein.Library @@ -21,6 +22,13 @@ namespace Serein.Library [PropertyInfo(IsProtection = true)] private NodeModelBase _nodeModel; + /// + /// 对应的程序集 + /// + [PropertyInfo] + private string _assemblyName; + + /// /// 是否保护参数(目前仅视觉效果参数,不影响运行实现,后续将设置作用在运行逻辑中) /// @@ -188,6 +196,7 @@ namespace Serein.Library { throw new ArgumentException("无效的节点类型"); } + AssemblyName = Info.AssemblyName; MethodName = Info.MethodName; MethodAnotherName = Info.MethodAnotherName; MethodDynamicType = nodeType; @@ -204,6 +213,7 @@ namespace Serein.Library { return new MethodDetailsInfo { + AssemblyName = this.AssemblyName, MethodName = this.MethodName, MethodAnotherName = this.MethodAnotherName, NodeType = this.MethodDynamicType.ToString(), @@ -222,6 +232,7 @@ namespace Serein.Library // this => 是元数据 var md = new MethodDetails( nodeModel) // 创建新节点时拷贝实例 { + AssemblyName = this.AssemblyName, ActingInstance = this.ActingInstance, ActingInstanceType = this.ActingInstanceType, MethodDynamicType = this.MethodDynamicType, @@ -231,8 +242,9 @@ namespace Serein.Library MethodLockName = this.MethodLockName, IsProtectionParameter = this.IsProtectionParameter, ParamsArgIndex = this.ParamsArgIndex, + ParameterDetailss = this.ParameterDetailss?.Select(p => p?.CloneOfModel(nodeModel)).ToArray(), // 拷贝属于节点方法的新入参描述 }; - md.ParameterDetailss = this.ParameterDetailss?.Select(p => p?.CloneOfModel(nodeModel)).ToArray(); // 拷贝属于节点方法的新入参描述 + return md; } diff --git a/Library/FlowNode/NodeModelBaseFunc.cs b/Library/FlowNode/NodeModelBaseFunc.cs index 7422210..faec818 100644 --- a/Library/FlowNode/NodeModelBaseFunc.cs +++ b/Library/FlowNode/NodeModelBaseFunc.cs @@ -52,6 +52,7 @@ namespace Serein.Library return new NodeInfo { Guid = Guid, + AssemblyName = MethodDetails.AssemblyName, MethodName = MethodDetails?.MethodName, Label = MethodDetails?.MethodAnotherName, Type = this.GetType().ToString(), @@ -316,7 +317,7 @@ namespace Serein.Library { throw new Exception($"节点{this.Guid}不存在方法信息,请检查是否需要重写节点的ExecutingAsync"); } - if (!context.Env.TryGetDelegateDetails(md.MethodName, out var dd)) + if (!context.Env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) { throw new Exception($"节点{this.Guid}不存在对应委托"); } diff --git a/Library/FlowNode/SereinProjectData.cs b/Library/FlowNode/SereinProjectData.cs index cbc1813..a6cab50 100644 --- a/Library/FlowNode/SereinProjectData.cs +++ b/Library/FlowNode/SereinProjectData.cs @@ -61,7 +61,7 @@ namespace Serein.Library /// 依赖的DLL /// - public Library[] Librarys { get; set; } + public NodeLibraryInfo[] Librarys { get; set; } /// /// 起始节点GUID @@ -132,38 +132,63 @@ namespace Serein.Library /// /// 项目依赖的程序集,项目文件相关 /// - public class Library + /// + public class NodeLibraryInfo { /// - /// 文件名称 + /// 文件名 /// - public string FileName { get; set; } /// - /// 文件路径 + /// 路径 /// public string FilePath { get; set; } /// - /// 程序集名称 + /// 所属的程序集名称 /// public string AssemblyName { get; set; } } + #region 暂时注释 + /*public class LibraryInfo +{ + /// + /// 文件名称 + /// + + public string FileName { get; set; } + + /// + /// 文件路径 + /// + public string FilePath { get; set; } + + /// + /// 程序集名称 + /// + public string AssemblyName { get; set; } +}*/ + #endregion + /// /// 节点信息,项目文件相关 /// public class NodeInfo { /// - /// GUID + /// 节点的GUID /// - public string Guid { get; set; } /// - /// 名称 + /// 节点方法所属的程序集名称 + /// + public string AssemblyName { get;set; } + + /// + /// 节点对应的名称 /// public string MethodName { get; set; } diff --git a/NodeFlow/Env/FlowEnvironment.cs b/NodeFlow/Env/FlowEnvironment.cs index 15aa873..495494f 100644 --- a/NodeFlow/Env/FlowEnvironment.cs +++ b/NodeFlow/Env/FlowEnvironment.cs @@ -9,6 +9,7 @@ using Serein.Library.Utils.SereinExpression; using Serein.NodeFlow.Model; using Serein.NodeFlow.Tool; using System.Collections.Concurrent; +using System.Diagnostics; using System.Numerics; using System.Reflection; using System.Reflection.Metadata.Ecma335; @@ -52,7 +53,8 @@ namespace Serein.NodeFlow.Env } }; - this.UIContextOperation = uiContextOperation; // 本地环境需要存放视图管理 + this.UIContextOperation = uiContextOperation; // 为加载的类库提供在UI线程上执行某些操作的封装工具类 + this.FlowLibraryManagement = new FlowLibraryManagement(this); // 实例化类库管理 } #region 远程管理 @@ -227,14 +229,16 @@ namespace Serein.NodeFlow.Env /// /// 通过程序集名称管理动态加载的程序集,用于节点创建提供方法描述,流程运行时提供Emit委托 /// - public ConcurrentDictionary FlowLibrarys { get; } = []; + private readonly FlowLibraryManagement FlowLibraryManagement; +#if false /// /// Library 与 MethodDetailss的依赖关系 /// public ConcurrentDictionary> MethodDetailsOfLibraryInfos { get; } = []; + /// /// 存储已加载的程序集 /// Key:程序集的FullName @@ -258,7 +262,8 @@ namespace Serein.NodeFlow.Env /// 存放所有通过Emit加载的委托 /// md.Methodname - delegate /// - private ConcurrentDictionary MethodDelegates { get; } = []; + private ConcurrentDictionary MethodDelegates { get; } = []; +#endif /// /// IOC对象容器管理 @@ -351,17 +356,13 @@ namespace Serein.NodeFlow.Env flowStarter = new FlowStarter(); var nodes = NodeModels.Values.ToList(); - List initMethods = []; - List loadMethods = []; - List exitMethods = []; + - var initMds = MethodDetailss.Values.Where(it => it.MethodDynamicType == NodeType.Init); - var loadMds = MethodDetailss.Values.Where(it => it.MethodDynamicType == NodeType.Loading); - var exitMds = MethodDetailss.Values.Where(it => it.MethodDynamicType == NodeType.Exit); + List initMethods = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Init); + List loadMethods = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Loading); + List exitMethods = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Exit); + Dictionary> autoRegisterTypes = this.FlowLibraryManagement.GetaAutoRegisterType(); - initMethods.AddRange(initMds); - loadMethods.AddRange(loadMds); - exitMethods.AddRange(exitMds); IOC.Reset(); // 开始运行时清空ioc中注册的实例 @@ -369,7 +370,7 @@ namespace Serein.NodeFlow.Env if (this.UIContextOperation is not null) IOC.CustomRegisterInstance(typeof(UIContextOperation).FullName, this.UIContextOperation, false); - await flowStarter.RunAsync(this, nodes, AutoRegisterTypes, initMethods, loadMethods, exitMethods); + await flowStarter.RunAsync(this, nodes, autoRegisterTypes, initMethods, loadMethods, exitMethods); if (FlipFlopState == RunState.Completion) { @@ -480,30 +481,9 @@ namespace Serein.NodeFlow.Env /// public async Task GetEnvInfoAsync() { - Dictionary> MdsOfLibraryInfos = []; - - foreach (var mdskv in MethodDetailsOfLibraryInfos) - { - var library = mdskv.Key; - var mds = mdskv.Value; - foreach (var md in mds) - { - if (!MdsOfLibraryInfos.TryGetValue(library, out var t_mds)) - { - t_mds = new List(); - MdsOfLibraryInfos[library] = t_mds; - } - var mdInfo = md.ToInfo(); - mdInfo.AssemblyName = library.AssemblyName; - t_mds.Add(mdInfo); - } - } - - LibraryMds[] libraryMdss = MdsOfLibraryInfos.Select(kv => new LibraryMds - { - AssemblyName = kv.Key.AssemblyName, - Mds = kv.Value.ToArray() - }).ToArray(); + // 获取所有的程序集对应的方法信息(程序集相关的数据) + var libraryMdss = this.FlowLibraryManagement.GetAllLibraryMds().ToArray(); + // 获取当前项目的信息(节点相关的数据) var project = await GetProjectInfoAsync(); Console.WriteLine("已将当前环境信息发送到远程客户端"); return new FlowEnvInfo @@ -540,13 +520,13 @@ namespace Serein.NodeFlow.Env foreach (var dllPath in dllPaths) { var dllFilePath = Path.GetFullPath(Path.Combine(filePath, dllPath)); - LoadDllNodeInfo(dllFilePath); + LoadDll(dllFilePath); // 加载项目文件时加载对应的程序集 } List<(NodeModelBase, string[])> regionChildNodes = new List<(NodeModelBase, string[])>(); List<(NodeModelBase, PositionOfUI)> ordinaryNodes = new List<(NodeModelBase, PositionOfUI)>(); // 加载节点 - foreach (var nodeInfo in projectData.Nodes) + foreach (NodeInfo? nodeInfo in projectData.Nodes) { var controlType = FlowFunc.GetNodeControlType(nodeInfo); if (controlType == NodeControlType.None) @@ -555,11 +535,14 @@ namespace Serein.NodeFlow.Env } else { - MethodDetails? methodDetails = null; - if (!string.IsNullOrEmpty(nodeInfo.MethodName)) + if (string.IsNullOrEmpty(nodeInfo.AssemblyName) && string.IsNullOrEmpty(nodeInfo.MethodName)) { - MethodDetailss.TryGetValue(nodeInfo.MethodName, out methodDetails);// 加载项目时尝试获取方法信息 + continue; } + MethodDetails? methodDetails = null; + FlowLibraryManagement.TryGetMethodDetails(nodeInfo.AssemblyName, + nodeInfo.MethodName, + out methodDetails); // 加载项目时尝试获取方法信息 var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载项目时创建节点 nodeModel.LoadInfo(nodeInfo); // 创建节点model if (nodeModel is null) @@ -726,7 +709,7 @@ namespace Serein.NodeFlow.Env { var projectData = new SereinProjectData() { - Librarys = LibraryInfos.Values.Select(lib => lib.ToLibrary()).ToArray(), + Librarys = this.FlowLibraryManagement.GetAllLibraryInfo().ToArray(), Nodes = NodeModels.Values.Select(node => node.ToInfo()).Where(info => info is not null).ToArray(), StartNode = NodeModels.Values.FirstOrDefault(it => it.IsStart)?.Guid, }; @@ -739,10 +722,11 @@ namespace Serein.NodeFlow.Env /// /// /// - // [AutoSocketHandle] public void LoadDll(string dllPath) { - LoadDllNodeInfo(dllPath); + (var libraryInfo, var mdInfos) = FlowLibraryManagement.LoadLibrary(dllPath); + UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(libraryInfo, mdInfos))); // 通知UI创建dll面板显示 + } /// @@ -752,49 +736,51 @@ namespace Serein.NodeFlow.Env /// public bool RemoteDll(string assemblyName) { - var library = LibraryInfos.Values.FirstOrDefault(nl => assemblyName.Equals(nl.AssemblyName)); - if (library is null) - { - return false; - } - var groupedNodes = NodeModels.Values - .Where(node => node.MethodDetails is not null) - .ToArray() - .GroupBy(node => node.MethodDetails?.MethodName) - .ToDictionary( - key => key.Key, - group => group.Count()); + return FlowLibraryManagement.UnloadLibrary(assemblyName); + + //var library = LibraryInfos.Values.FirstOrDefault(nl => assemblyName.Equals(nl.AssemblyName)); + //if (library is null) + //{ + // return false; + //} + //var groupedNodes = NodeModels.Values + // .Where(node => node.MethodDetails is not null) + // .ToArray() + // .GroupBy(node => node.MethodDetails?.MethodName) + // .ToDictionary( + // key => key.Key, + // group => group.Count()); - if (NodeModels.Count == 0) - { - return true; // 当前无节点,可以直接删除 - } + //if (NodeModels.Count == 0) + //{ + // return true; // 当前无节点,可以直接删除 + //} - if (MethodDetailsOfLibraryInfos.TryGetValue(library, out var mds)) // 存在方法 - { - foreach (var md in mds) - { - if (groupedNodes.TryGetValue(md.MethodName, out int count)) - { - if (count > 0) - { - return false; // 创建过相关的节点,无法移除 - } - } - } - // 开始移除相关信息 - foreach (var md in mds) - { - MethodDetailss.TryRemove(md.MethodName, out _); - } - MethodDetailsOfLibraryInfos.TryRemove(library, out _); - return true; - } - else - { - return true; - } + //if (MethodDetailsOfLibraryInfos.TryGetValue(library, out var mds)) // 存在方法 + //{ + // foreach (var md in mds) + // { + // if (groupedNodes.TryGetValue(md.MethodName, out int count)) + // { + // if (count > 0) + // { + // return false; // 创建过相关的节点,无法移除 + // } + // } + // } + // // 开始移除相关信息 + // foreach (var md in mds) + // { + // MethodDetailss.TryRemove(md.MethodName, out _); + // } + // MethodDetailsOfLibraryInfos.TryRemove(library, out _); + // return true; + //} + //else + //{ + // return true; + //} } @@ -814,7 +800,9 @@ namespace Serein.NodeFlow.Env } else { - if (MethodDetailss.TryGetValue(methodDetailsInfo.MethodName, out var methodDetails)) + if (FlowLibraryManagement.TryGetMethodDetails(methodDetailsInfo.AssemblyName, + methodDetailsInfo.MethodName, + out var methodDetails)) { nodeModel = FlowFunc.CreateNode(this, nodeControlType, methodDetails); // 一般的加载节点方法 } @@ -1026,25 +1014,18 @@ namespace Serein.NodeFlow.Env /// 获取方法描述 /// - public bool TryGetMethodDetailsInfo(string name, out MethodDetailsInfo? md) + public bool TryGetMethodDetailsInfo(string assemblyName, string methodName, out MethodDetailsInfo? mdInfo) { - if (!string.IsNullOrEmpty(name)) + var isPass = FlowLibraryManagement.TryGetMethodDetails(assemblyName, methodName, out var md); + if (!isPass || md is null) { - foreach (var t_md in MethodDetailss.Values) - { - md = t_md.ToInfo(); - if (md != null) - { - return true; - } - } - md = null; + mdInfo = null; return false; } else { - md = null; - return false; + mdInfo = md?.ToInfo(); + return true; } } @@ -1058,18 +1039,9 @@ namespace Serein.NodeFlow.Env /// /// /// - public bool TryGetDelegateDetails(string methodName, out DelegateDetails? delegateDetails) + public bool TryGetDelegateDetails(string assemblyName, string methodName, out DelegateDetails? delegateDetails) { - - if (!string.IsNullOrEmpty(methodName) && MethodDelegates.TryGetValue(methodName, out delegateDetails)) - { - return delegateDetails != null; - } - else - { - delegateDetails = null; - return false; - } + return FlowLibraryManagement.TryGetDelegateDetails(assemblyName, methodName, out delegateDetails); } @@ -1399,6 +1371,8 @@ namespace Serein.NodeFlow.Env #region 私有方法 + #region 暂时注释 + /* /// /// 加载指定路径的DLL文件 /// @@ -1455,7 +1429,8 @@ namespace Serein.NodeFlow.Env - } + }*/ + #endregion /// /// 移除连接关系 @@ -1507,7 +1482,8 @@ namespace Serein.NodeFlow.Env return true; } - /// + #region 暂时注释 + /*/// /// 动态加载程序集 /// /// 程序集本身 @@ -1597,7 +1573,8 @@ namespace Serein.NodeFlow.Env Console.WriteLine(ex.ToString()); return ([], []); } - } + }*/ + #endregion /// /// 创建节点 diff --git a/NodeFlow/Env/FlowEnvironmentDecorator.cs b/NodeFlow/Env/FlowEnvironmentDecorator.cs index c46f69b..ff5c22d 100644 --- a/NodeFlow/Env/FlowEnvironmentDecorator.cs +++ b/NodeFlow/Env/FlowEnvironmentDecorator.cs @@ -390,14 +390,14 @@ namespace Serein.NodeFlow.Env currentFlowEnvironment.TriggerInterrupt(nodeGuid, expression, type); } - public bool TryGetDelegateDetails(string methodName, out DelegateDetails del) + public bool TryGetDelegateDetails(string libraryName, string methodName, out DelegateDetails del) { - return currentFlowEnvironment.TryGetDelegateDetails(methodName, out del); + return currentFlowEnvironment.TryGetDelegateDetails(libraryName, methodName, out del); } - public bool TryGetMethodDetailsInfo(string methodName, out MethodDetailsInfo mdInfo) + public bool TryGetMethodDetailsInfo(string libraryName, string methodName, out MethodDetailsInfo mdInfo) { - return currentFlowEnvironment.TryGetMethodDetailsInfo(methodName, out mdInfo); + return currentFlowEnvironment.TryGetMethodDetailsInfo(libraryName, methodName, out mdInfo); } public void WriteLineObjToJson(object obj) diff --git a/NodeFlow/Env/FlowFunc.cs b/NodeFlow/Env/FlowFunc.cs index 687ebc5..e7ec836 100644 --- a/NodeFlow/Env/FlowFunc.cs +++ b/NodeFlow/Env/FlowFunc.cs @@ -89,13 +89,11 @@ namespace Serein.NodeFlow.Env /// /// /// - public static Library.Library ToLibrary(this Library.NodeLibraryInfo libraryInfo) + public static NodeLibraryInfo ToLibrary(this Library.NodeLibraryInfo libraryInfo) { - //var tmp = library.Assembly.ManifestModule.Name; - return new Library.Library + return new NodeLibraryInfo { AssemblyName = libraryInfo.AssemblyName, - //AssemblyName = library.Assembly.GetName().Name, FileName = libraryInfo.FileName, FilePath = libraryInfo.FilePath, }; diff --git a/NodeFlow/Env/RemoteFlowEnvironment.cs b/NodeFlow/Env/RemoteFlowEnvironment.cs index 82c4746..393c31f 100644 --- a/NodeFlow/Env/RemoteFlowEnvironment.cs +++ b/NodeFlow/Env/RemoteFlowEnvironment.cs @@ -129,6 +129,7 @@ namespace Serein.NodeFlow.Env { AssemblyName = lib.AssemblyName, FilePath = "Remote", + FileName = "Remote", }; var mdInfos = lib.Mds.ToList(); UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibraryInfo, mdInfos))); // 通知UI创建dll面板显示 @@ -791,14 +792,14 @@ namespace Serein.NodeFlow.Env return ChannelFlowInterrupt.CancelType.Error; } - public bool TryGetMethodDetailsInfo(string methodName, out MethodDetailsInfo mdInfo) + public bool TryGetMethodDetailsInfo(string libraryName, string methodName, out MethodDetailsInfo mdInfo) { Console.WriteLine("远程环境尚未实现的接口:TryGetMethodDetailsInfo"); mdInfo = null; return false; } - public bool TryGetDelegateDetails(string methodName, out DelegateDetails del) + public bool TryGetDelegateDetails(string libraryName, string methodName, out DelegateDetails del) { Console.WriteLine("远程环境尚未实现的接口:TryGetDelegateDetails"); del = null; diff --git a/NodeFlow/FlowStarter.cs b/NodeFlow/FlowStarter.cs index 961b110..96474b0 100644 --- a/NodeFlow/FlowStarter.cs +++ b/NodeFlow/FlowStarter.cs @@ -184,7 +184,7 @@ namespace Serein.NodeFlow //object?[]? args = [Context]; foreach (var md in initMethods) // 初始化 { - if (!env.TryGetDelegateDetails(md.MethodName, out var dd)) + if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) { throw new Exception("不存在对应委托"); } @@ -205,7 +205,7 @@ namespace Serein.NodeFlow { //object?[]? data = [md.ActingInstance, args]; //md.MethodDelegate.DynamicInvoke(data); - if (!env.TryGetDelegateDetails(md.MethodName, out var dd)) + if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) { throw new Exception("不存在对应委托"); } @@ -228,7 +228,7 @@ namespace Serein.NodeFlow foreach (MethodDetails? md in exitMethods) { - if (!env.TryGetDelegateDetails(md.MethodName, out var dd)) + if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) { throw new Exception("不存在对应委托"); } diff --git a/NodeFlow/Model/CompositeConditionNode.cs b/NodeFlow/Model/CompositeConditionNode.cs index 316fe12..788067b 100644 --- a/NodeFlow/Model/CompositeConditionNode.cs +++ b/NodeFlow/Model/CompositeConditionNode.cs @@ -111,7 +111,8 @@ namespace Serein.NodeFlow.Model return new NodeInfo { Guid = Guid, - MethodName = MethodDetails?.MethodName, + AssemblyName = MethodDetails.AssemblyName, + MethodName = MethodDetails.MethodName, Label = MethodDetails?.MethodAnotherName, Type = this.GetType().ToString(), TrueNodes = trueNodes.ToArray(), diff --git a/NodeFlow/Model/SingleFlipflopNode.cs b/NodeFlow/Model/SingleFlipflopNode.cs index f6b99fe..b213c75 100644 --- a/NodeFlow/Model/SingleFlipflopNode.cs +++ b/NodeFlow/Model/SingleFlipflopNode.cs @@ -43,7 +43,7 @@ namespace Serein.NodeFlow.Model #endregion MethodDetails md = MethodDetails; - if (!context.Env.TryGetDelegateDetails(md.MethodName, out var dd)) + if (!context.Env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) { throw new Exception("不存在对应委托"); } diff --git a/NodeFlow/Tool/FlowLibrary.cs b/NodeFlow/Tool/FlowLibrary.cs new file mode 100644 index 0000000..4754353 --- /dev/null +++ b/NodeFlow/Tool/FlowLibrary.cs @@ -0,0 +1,230 @@ +using Serein.Library; +using Serein.NodeFlow.Tool; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Serein.NodeFlow +{ + + /// + /// + /// + public class FlowLibrary + { + private readonly Assembly assembly; + private readonly Action actionOfUnloadAssmbly; + private string _assemblyFilePath; + + public FlowLibrary(string assemblyFilePath, + Assembly assembly, + Action actionOfUnloadAssmbly) + { + this._assemblyFilePath = assemblyFilePath; + this.assembly = assembly; + this.actionOfUnloadAssmbly = actionOfUnloadAssmbly; + LoadAssembly(assembly); + } + + + public string FullName => assembly.GetName().FullName; + + public string Version => assembly.GetName().Version.ToString(); + + /// + /// 加载程序集时创建的方法描述 + /// + public ConcurrentDictionary MethodDetailss { get; } = new ConcurrentDictionary(); + + /// + /// 管理通过Emit动态构建的委托 + /// + public ConcurrentDictionary DelegateDetailss { get; } = new ConcurrentDictionary(); + + /// + /// 记录不同的注册时机需要自动创建全局唯一实例的类型信息 + /// + public ConcurrentDictionary> RegisterTypes { get; } = new ConcurrentDictionary>(); + + + /// + /// 卸载当前程序集以及附带的所有信息 + /// + public void Upload() + { + actionOfUnloadAssmbly?.Invoke(); + } + + public NodeLibraryInfo ToInfo() + { + return new NodeLibraryInfo + { + AssemblyName = FullName, + FileName = Path.GetFileName(_assemblyFilePath), + FilePath = _assemblyFilePath, + }; + } + + + //public void LoadAssmely(Assembly assembly) + //{ + // (var registerTypes, var mdlist) = LoadAssembly2(assembly); + // if (mdlist.Count > 0) + // { + // var nodeLibraryInfo = new NodeLibraryInfo + // { + // //Assembly = assembly, + // AssemblyName = assembly.FullName, + // FileName = Path.GetFileName(_assemblyFilePath), + // FilePath = _assemblyFilePath, + // }; + + // //LibraryInfos.TryAdd(nodeLibraryInfo.AssemblyName, nodeLibraryInfo); + + // MethodDetailss.TryAdd(nodeLibraryInfo.AssemblyName, mdlist); + + // foreach (var md in mdlist) + // { + // MethodDetailss.TryAdd(md.MethodName, md); + // } + + // foreach (var kv in registerTypes) + // { + // if (!RegisterTypes.TryGetValue(kv.Key, out var types)) + // { + // types = new List(); + // RegisterTypes.TryAdd(kv.Key, types); + // } + // types.AddRange(kv.Value); + // } + // var mdInfos = mdlist.Select(md => md.ToInfo()).ToList(); // 转换成方法信息 + // } + //} + + + /// + /// 动态加载程序集 + /// + /// 程序集本身 + /// + private bool LoadAssembly(Assembly assembly) + { + #region 检查入参 + + // 加载DLL,创建 MethodDetails、实例作用对象、委托方法 + var assemblyName = assembly.GetName().Name; + if (string.IsNullOrEmpty(assemblyName)) // 防止动态程序集没有定义程序集名称 + { + return false; + } + + List types = assembly.GetTypes().ToList(); // 获取程序集中的所有类型 + if (types.Count < 0) // 防止动态程序集中没有类型信息? + { + return false; + } + + #endregion + + + try + { + + + #region 获取 DynamicFlow 特性的流程控制器,如果没有退出 + // Type : 具有 DynamicFlowAttribute 标记的类型 + // string : 类型元数据 DynamicFlowAttribute 特性中的 Name 属性 (用于生成方法描述时,添加在方法别名中提高可读性) + List<(Type Type, string Name)> scanTypes = new List<(Type Type, string Name)>(); + + // (Type, string) + // Type : 具有 DynamicFlowAttribute 标记的类型 + // string : 类型元数据 DynamicFlowAttribute 特性中的 Name 属性 + foreach (var type in types) + { + if (type.GetCustomAttribute() is DynamicFlowAttribute dynamicFlowAttribute && dynamicFlowAttribute.Scan == true) + { + scanTypes.Add((type, dynamicFlowAttribute.Name)); + } + } + if (scanTypes.Count == 0) + { + // 类型没有流程控制器 + return false; + } + #endregion + + + #region 创建对应的方法元数据 + // 从 scanTypes.Type 创建的方法信息 + // Md : 方法描述 + // Dd :方法对应的Emit委托 + List<(MethodDetails Md, DelegateDetails Dd)> detailss = new List<(MethodDetails Md, DelegateDetails Dd)>(); + + // 遍历扫描的类型 + foreach ((var type, var flowName) in scanTypes) + { + var methodInfos = NodeMethodDetailsHelper.GetMethodsToProcess(type); + foreach (var methodInfo in methodInfos) // 遍历流程控制器类型中的方法信息 + { + // 尝试创建 + if (!NodeMethodDetailsHelper.TryCreateDetails(type, methodInfo, assemblyName, + out var md, out var dd)) // 返回的描述 + { + Console.WriteLine($"无法加载方法信息:{assemblyName}-{type}-{methodInfo}"); + continue; + } + md.MethodAnotherName = flowName + md.MethodAnotherName; // 方法别名 + detailss.Add((md, dd)); + } + } + + #endregion + + #region 检查是否成功加载,如果成功,则真正写入到缓存的集合中 + if(detailss.Count == 0) + { + return false; + } + #region 加载成功,缓存所有方法、委托的信息 + foreach((var md,var dd) in detailss) + { + MethodDetailss.TryAdd(md.MethodName, md); + DelegateDetailss.TryAdd(md.MethodName, dd); + } + + #endregion + #region 加载成功,开始获取并记录所有需要自动实例化的类型(在流程启动时) + foreach (Type type in types) + { + if (type.GetCustomAttribute() is AutoRegisterAttribute attribute) + { + if (!RegisterTypes.TryGetValue(attribute.Class, out var valus)) + { + valus = new List(); + RegisterTypes.TryAdd(attribute.Class, valus); + } + valus.Add(type); + } + } + #endregion + + #endregion + + return true; + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + return false; + } + } + + + } + +} diff --git a/NodeFlow/Tool/FlowLibraryLoader.cs b/NodeFlow/Tool/FlowLibraryLoader.cs deleted file mode 100644 index e1e2115..0000000 --- a/NodeFlow/Tool/FlowLibraryLoader.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Runtime.Loader; -using System.Text; -using System.Threading.Tasks; - -namespace Serein.NodeFlow.Tool -{ - /// - /// 管理加载在流程的程序集 - /// - public class FlowLibraryLoader : AssemblyLoadContext - { - private Assembly _pluginAssembly; - - public string FullName => _pluginAssembly.FullName; - - /// - /// 加载程序集 - /// - /// - public FlowLibraryLoader(string pluginPath) : base(isCollectible: true) - { - _pluginAssembly = LoadFromAssemblyPath(pluginPath); - } - - /// - /// 保持默认加载行为 - /// - /// - /// - - protected override Assembly Load(AssemblyName assemblyName) - { - return null; // 保持默认加载行为 - } - - - public List LoadFlowTypes() - { - return _pluginAssembly.GetTypes().ToList(); - } - - /// - /// 是否对程序集的引用 - /// - public void UnloadPlugin() - { - _pluginAssembly = null; // 释放对程序集的引用 - Unload(); // 触发卸载 - // 强制进行垃圾回收,以便完成卸载 - GC.Collect(); - GC.WaitForPendingFinalizers(); - } - } - - - -} diff --git a/NodeFlow/Tool/FlowLibraryManagement.cs b/NodeFlow/Tool/FlowLibraryManagement.cs new file mode 100644 index 0000000..aeddad1 --- /dev/null +++ b/NodeFlow/Tool/FlowLibraryManagement.cs @@ -0,0 +1,264 @@ +using Serein.Library; +using Serein.Library.Api; +using Serein.Library.FlowNode; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Runtime.Loader; +using System.Text; +using System.Threading.Tasks; + +namespace Serein.NodeFlow.Tool +{ + /// + /// 管理加载在运行环境中的外部程序集 + /// + public class FlowLibraryManagement + { + public FlowLibraryManagement(IFlowEnvironment flowEnvironment) + { + this.flowEnvironment = flowEnvironment; + } + + private readonly IFlowEnvironment flowEnvironment; + + /// + /// 缓存所有加载了的程序集 + /// + private ConcurrentDictionary _myFlowLibrarys = new ConcurrentDictionary(); + + public (NodeLibraryInfo,List) LoadLibrary(string libraryfilePath) + { + return LoadDllNodeInfo(libraryfilePath); + } + + public bool UnloadLibrary(string libraryName) + { + if (_myFlowLibrarys.TryGetValue(libraryName, out var flowLibrary)) + { + try + { + flowLibrary.Upload(); + return true; + } + catch (Exception ex) + { + Console.WriteLine($"尝试卸载程序集[{libraryName}]发生错误:{ex}"); + return false; + } + + } + else + { + return false; + } + } + + /// + /// 获取方法描述 + /// + /// 程序集名称 + /// 方法名称 + /// 返回的方法描述 + /// 是否获取成功 + public bool TryGetMethodDetails(string assemblyName, string methodName, [MaybeNullWhen(false)] out MethodDetails md) + { + if(_myFlowLibrarys.TryGetValue(assemblyName, out var flowLibrary) + && flowLibrary.MethodDetailss.TryGetValue(methodName,out md)) + { + return true; + } + else + { + md = null; + return false; + } + } + + /// + /// 获取方法调用的委托 + /// + /// 程序集名称 + /// 方法名称 + /// 返回的委托调用封装类 + /// 是否获取成功 + public bool TryGetDelegateDetails(string assemblyName, string methodName, [MaybeNullWhen(false)] out DelegateDetails dd) + { + if (_myFlowLibrarys.TryGetValue(assemblyName, out var flowLibrary) + && flowLibrary.DelegateDetailss.TryGetValue(methodName, out dd)) + { + return true; + } + else + { + dd = null; + return false; + } + } + + + /// + /// 获取(初始化/加载时/退出后)相应的节点方法 + /// + /// + /// + public List GetMdsOnFlowStart(NodeType nodeType) + { + List mds = []; + + foreach (var library in _myFlowLibrarys.Values) + { + var t_mds = library.MethodDetailss.Values.Where(it => it.MethodDynamicType == nodeType).ToList(); + mds.AddRange(t_mds); + } + return mds; + } + + /// + /// 获取流程启动时在不同时间点需要自动实例化的类型 + /// + /// + public Dictionary> GetaAutoRegisterType() + { + Dictionary> rsTypes = new Dictionary>(); + foreach(var library in _myFlowLibrarys.Values) + { + foreach(var kv in library.RegisterTypes) + { + var @class = kv.Key; + var type = kv.Value; + if(!rsTypes.TryGetValue(@class, out var tmpTypes)) + { + tmpTypes = new List(); + rsTypes.Add(@class, tmpTypes); + } + tmpTypes.AddRange(type); + } + } + return rsTypes; + } + + + /// + /// 获取所有方法信息,用于保存项目时调用 + /// + /// + public List GetAllLibraryMds() + { + List mds = new List(); + foreach (FlowLibrary library in _myFlowLibrarys.Values) + { + var tmp = new LibraryMds { + AssemblyName = library.FullName, + Mds = library.MethodDetailss.Values.Select(md => md.ToInfo()).ToArray() + }; + mds.Add(tmp); + } + return mds; + } + + + + + + /// + /// 序列化当前项目的依赖信息、节点信息,用于远程登录的场景,需要将依赖信息从本地(受控端)发送到远程(主控端) + /// + /// + public List GetAllLibraryInfo() + { + return _myFlowLibrarys.Values.Select(library => library.ToInfo()).ToList(); + } + + + #region 功能性方法 + + /// + /// 从文件路径中加载程序集,返回相应的信息 + /// + /// + /// + private (NodeLibraryInfo, List) LoadDllNodeInfo(string dllPath) + { + + + var fileName = Path.GetFileName(dllPath); // 获取文件名 + Assembly assembly = Assembly.LoadFrom(dllPath); // 加载程序集 + FlowLibrary flowLibrary = new FlowLibrary(dllPath, assembly, () => + { + Console.WriteLine("暂未实现卸载程序集"); + //flowAlc.Unload(); // 卸载程序集 + //flowAlc = null; + //GC.Collect(); // 强制触发GC确保卸载成功 + //GC.WaitForPendingFinalizers(); + }); + + _myFlowLibrarys.TryAdd(assembly.GetName().Name, flowLibrary); + + (NodeLibraryInfo, List) result = (flowLibrary.ToInfo(), + flowLibrary.MethodDetailss.Values.Select(md => md.ToInfo()).ToList()); + return result; + + +#if false + var fileName = Path.GetFileName(dllPath); // 获取文件名 + var flowAlc = new AssemblyLoadContext(fileName, true); + flowAlc.LoadFromAssemblyPath(dllPath); // 加载指定路径的程序集 + flowAlc.LoadFromAssemblyPath(@"F:\临时\project\yolo flow\OpenCvSharp.dll"); // 加载指定路径的程序集 + + var assemblt = flowAlc.Assemblies.ToArray()[0]; // 目前只会加载一个程序集,所以这样获取 + FlowLibrary flowLibrary = new FlowLibrary(dllPath, assemblt, () => + { + flowAlc.Unload(); // 卸载程序集 + flowAlc = null; + GC.Collect(); // 强制触发GC确保卸载成功 + GC.WaitForPendingFinalizers(); + }); + _myFlowLibrarys.TryAdd(assemblt.GetName().Name, flowLibrary); + return flowLibrary.ToInfo(); + + + //foreach (var assemblt in flowAlc.Assemblies) + //{ + // FlowLibrary flowLibrary = new FlowLibrary(dllPath, assemblt, () => + // { + // flowAlc.Unload(); // 卸载程序集 + // flowAlc = null; + // GC.Collect(); // 强制触发GC确保卸载成功 + // GC.WaitForPendingFinalizers(); + // }); + //} + +#endif + //if (OperatingSystem.IsWindows()) + //{ + // UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibraryInfo, mdInfos))); // 通知UI创建dll面板显示 + + //} + } + + + + #endregion + + + + ///// + ///// 是否对程序集的引用 + ///// + //public void UnloadPlugin() + //{ + // _pluginAssembly = null; // 释放对程序集的引用 + // Unload(); // 触发卸载 + // // 强制进行垃圾回收,以便完成卸载 + // GC.Collect(); + // GC.WaitForPendingFinalizers(); + //} + } + + + +} diff --git a/NodeFlow/Tool/NodeMethodDetailsHelper.cs b/NodeFlow/Tool/NodeMethodDetailsHelper.cs index 9e88725..45edc57 100644 --- a/NodeFlow/Tool/NodeMethodDetailsHelper.cs +++ b/NodeFlow/Tool/NodeMethodDetailsHelper.cs @@ -5,6 +5,7 @@ using System.Collections.Concurrent; using System.Reflection; using Serein.Library.FlowNode; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace Serein.NodeFlow.Tool; @@ -21,21 +22,35 @@ public static class NodeMethodDetailsHelper } /// - /// 创建方法信息 + /// 创建方法信息/委托信息 /// - /// - public static (MethodDetails?, DelegateDetails?) CreateMethodDetails(Type type, MethodInfo method, string assemblyName) + /// 方法所属的类型 + /// 方法信息 + /// 方法所属的程序集名称 + /// 创建的方法描述,用来生成节点信息 + /// 方法对应的Emit动态委托 + /// 指示是否创建成功 + public static bool TryCreateDetails(Type type, + MethodInfo methodInfo, + string assemblyName, + [MaybeNullWhen(false)] out MethodDetails methodDetails, + [MaybeNullWhen(false)] out DelegateDetails delegateDetails) { - var attribute = method.GetCustomAttribute(); + + + var attribute = methodInfo.GetCustomAttribute(); if(attribute is null || attribute.Scan == false) { - return (null, null); + methodDetails = null; + delegateDetails = null; + return false; } - //var dllTypeName = $"{assemblyName}.{type.Name}"; - var dllTypeMethodName = $"{assemblyName}.{type.Name}.{method.Name}"; - Console.WriteLine("loading method : " +dllTypeMethodName); - Debug.WriteLine("loading method : " +dllTypeMethodName); - var explicitDataOfParameters = GetExplicitDataOfParameters(method.GetParameters()); + + var methodName = $"{assemblyName}.{type.Name}.{methodInfo.Name}"; + Console.WriteLine("loading method : " + methodName); + + // 创建参数信息 + var explicitDataOfParameters = GetExplicitDataOfParameters(methodInfo.GetParameters()); @@ -46,17 +61,17 @@ public static class NodeMethodDetailsHelper // method.ReturnType);// 返回值 //// 通过表达式树生成委托 - var emitMethodType = EmitHelper.CreateDynamicMethod(method, out var methodDelegate);// 返回值 + var emitMethodType = EmitHelper.CreateDynamicMethod(methodInfo, out var methodDelegate);// 返回值 Type? returnType; - bool isTask = IsGenericTask(method.ReturnType, out var taskResult); + bool isTask = IsGenericTask(methodInfo.ReturnType, out var taskResult); if (attribute.MethodDynamicType == Library.NodeType.Flipflop) { - if (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) + if (methodInfo.ReturnType.IsGenericType && methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) { // 获取 Task<> 的泛型参数类型 - var innerType = method.ReturnType.GetGenericArguments()[0]; + var innerType = methodInfo.ReturnType.GetGenericArguments()[0]; if (innerType.IsGenericType && innerType.GetGenericTypeDefinition() == typeof(IFlipflopContext<>)) { var flipflopType = innerType.GetGenericArguments()[0]; @@ -64,14 +79,18 @@ public static class NodeMethodDetailsHelper } else { - Console.WriteLine($"[{dllTypeMethodName}]跳过创建,返回类型非预期的Task>。"); - return (null, null); + Console.WriteLine($"[{methodName}]跳过创建,返回类型非预期的Task>。"); + methodDetails = null; + delegateDetails = null; + return false; } } else { - Console.WriteLine($"[{dllTypeMethodName}]跳过创建,因为触发器方法的返回值并非Task<>,将无法等待。"); - return (null, null); + Console.WriteLine($"[{methodName}]跳过创建,因为触发器方法的返回值并非Task<>,将无法等待。"); + methodDetails = null; + delegateDetails = null; + return false; } //if (!isTask || taskResult != typeof(IFlipflopContext)) @@ -86,11 +105,11 @@ public static class NodeMethodDetailsHelper } else { - returnType = method.ReturnType; + returnType = methodInfo.ReturnType; } if (string.IsNullOrEmpty(attribute.AnotherName)){ - attribute.AnotherName = method.Name; + attribute.AnotherName = methodInfo.Name; } @@ -107,18 +126,22 @@ public static class NodeMethodDetailsHelper var md = new MethodDetails() // 从DLL生成方法描述(元数据) { ActingInstanceType = type, - // ActingInstance = instance, - MethodName = dllTypeMethodName, + // ActingInstance = instance, + MethodName = methodName, + AssemblyName = assemblyName, MethodDynamicType = attribute.MethodDynamicType, MethodLockName = attribute.LockName, MethodAnotherName = methodMethodAnotherName, ParameterDetailss = explicitDataOfParameters, ReturnType = returnType, // 如果存在可变参数,取最后一个元素的下标,否则为-1; - ParamsArgIndex = hasParamsArg ? explicitDataOfParameters.Length-1 : -1, + ParamsArgIndex = hasParamsArg ? explicitDataOfParameters.Length - 1 : -1, }; var dd = new DelegateDetails(emitMethodType, methodDelegate) ; - return (md, dd); + + methodDetails = md; + delegateDetails = dd; + return true; } diff --git a/WorkBench/MainWindow.xaml.cs b/WorkBench/MainWindow.xaml.cs index fc0e987..b8621aa 100644 --- a/WorkBench/MainWindow.xaml.cs +++ b/WorkBench/MainWindow.xaml.cs @@ -2505,7 +2505,7 @@ namespace Serein.Workbench Console.WriteLine(savePath); for (int index = 0; index < projectData.Librarys.Length; index++) { - Library.Library? library = projectData.Librarys[index]; + NodeLibraryInfo? library = projectData.Librarys[index]; try { string targetPath = System.IO.Path.Combine(librarySavePath, library.FileName); // 目标文件夹