mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-05-01 03:53:22 +08:00
改写了流程依赖管理,封装为一个工具类,将来计划实现动态增加卸载/更新类库的功能
This commit is contained in:
@@ -676,8 +676,8 @@ namespace Serein.Library.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移除DLL
|
/// 移除DLL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="assemblyName">程序集的名称</param>
|
/// <param name="assemblyFullName">程序集的名称</param>
|
||||||
bool RemoteDll(string assemblyName);
|
bool RemoteDll(string assemblyFullName);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 清理加载的DLL(待更改)
|
/// 清理加载的DLL(待更改)
|
||||||
@@ -860,7 +860,7 @@ namespace Serein.Library.Api
|
|||||||
/// <param name="methodName">方法描述</param>
|
/// <param name="methodName">方法描述</param>
|
||||||
/// <param name="mdInfo">方法信息</param>
|
/// <param name="mdInfo">方法信息</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
bool TryGetMethodDetailsInfo(string methodName, out MethodDetailsInfo mdInfo);
|
bool TryGetMethodDetailsInfo(string libraryName, string methodName, out MethodDetailsInfo mdInfo);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取指定方法的Emit委托
|
/// 获取指定方法的Emit委托
|
||||||
@@ -868,7 +868,7 @@ namespace Serein.Library.Api
|
|||||||
/// <param name="methodName"></param>
|
/// <param name="methodName"></param>
|
||||||
/// <param name="del"></param>
|
/// <param name="del"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
bool TryGetDelegateDetails(string methodName, out DelegateDetails del);
|
bool TryGetDelegateDetails(string libraryName, string methodName, out DelegateDetails del);
|
||||||
|
|
||||||
|
|
||||||
#region 远程相关
|
#region 远程相关
|
||||||
|
|||||||
@@ -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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 节点DLL依赖类,如果一个项目中引入了多个DLL,需要放置在同一个文件夹中
|
|
||||||
/// </summary>
|
|
||||||
public class NodeLibraryInfo
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 文件名
|
|
||||||
/// </summary>
|
|
||||||
public string FileName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 路径
|
|
||||||
/// </summary>
|
|
||||||
public string FilePath { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 所属的程序集名称
|
|
||||||
/// </summary>
|
|
||||||
public string AssemblyName{ get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public class FlowLibrary
|
|
||||||
{
|
|
||||||
public FlowLibrary(string assemblyName,
|
|
||||||
Action actionOfUnloadAssmbly)
|
|
||||||
{
|
|
||||||
this.AssemblyName = assemblyName;
|
|
||||||
this.actionOfUnloadAssmbly = actionOfUnloadAssmbly;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string AssemblyName { get; }
|
|
||||||
|
|
||||||
//public string AssemblyVersion { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 加载程序集时创建的方法描述
|
|
||||||
/// </summary>
|
|
||||||
public ConcurrentDictionary<string, MethodDetails> MethodDetailss { get; } = new ConcurrentDictionary<string, MethodDetails>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 管理通过Emit动态构建的委托
|
|
||||||
/// </summary>
|
|
||||||
public ConcurrentDictionary<string, DelegateDetails> DelegateDetailss { get; } = new ConcurrentDictionary<string, DelegateDetails>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 记录不同的注册时机需要自动创建全局唯一实例的类型信息
|
|
||||||
/// </summary>
|
|
||||||
public ConcurrentDictionary<RegisterSequence, Type[]> RegisterTypes { get; } = new ConcurrentDictionary<RegisterSequence, Type[]>();
|
|
||||||
|
|
||||||
|
|
||||||
private readonly Action actionOfUnloadAssmbly;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 卸载当前程序集以及附带的所有信息
|
|
||||||
/// </summary>
|
|
||||||
public void Upload()
|
|
||||||
{
|
|
||||||
actionOfUnloadAssmbly?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 通过方法名称获取对应的Emit委托(元数据),用于动态调用节点对应的方法
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="methodName">方法名称</param>
|
|
||||||
/// <param name="dd">Emit委托</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool GetDelegateDetails(string methodName, out DelegateDetails dd)
|
|
||||||
{
|
|
||||||
return DelegateDetailss.TryGetValue(methodName, out dd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 通过方法名称获取对应的方法描述(元数据),用于创建节点时,节点实例需要的方法描述
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="methodName">方法名称</param>
|
|
||||||
/// <param name="md">方法描述</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool GetMethodDetails(string methodName, out MethodDetails md)
|
|
||||||
{
|
|
||||||
return MethodDetailss.TryGetValue(methodName, out md);
|
|
||||||
}
|
|
||||||
|
|
||||||
public NodeLibraryInfo ToInfo()
|
|
||||||
{
|
|
||||||
return new NodeLibraryInfo
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Serein.Library
|
namespace Serein.Library
|
||||||
@@ -21,6 +22,13 @@ namespace Serein.Library
|
|||||||
[PropertyInfo(IsProtection = true)]
|
[PropertyInfo(IsProtection = true)]
|
||||||
private NodeModelBase _nodeModel;
|
private NodeModelBase _nodeModel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 对应的程序集
|
||||||
|
/// </summary>
|
||||||
|
[PropertyInfo]
|
||||||
|
private string _assemblyName;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否保护参数(目前仅视觉效果参数,不影响运行实现,后续将设置作用在运行逻辑中)
|
/// 是否保护参数(目前仅视觉效果参数,不影响运行实现,后续将设置作用在运行逻辑中)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -188,6 +196,7 @@ namespace Serein.Library
|
|||||||
{
|
{
|
||||||
throw new ArgumentException("无效的节点类型");
|
throw new ArgumentException("无效的节点类型");
|
||||||
}
|
}
|
||||||
|
AssemblyName = Info.AssemblyName;
|
||||||
MethodName = Info.MethodName;
|
MethodName = Info.MethodName;
|
||||||
MethodAnotherName = Info.MethodAnotherName;
|
MethodAnotherName = Info.MethodAnotherName;
|
||||||
MethodDynamicType = nodeType;
|
MethodDynamicType = nodeType;
|
||||||
@@ -204,6 +213,7 @@ namespace Serein.Library
|
|||||||
{
|
{
|
||||||
return new MethodDetailsInfo
|
return new MethodDetailsInfo
|
||||||
{
|
{
|
||||||
|
AssemblyName = this.AssemblyName,
|
||||||
MethodName = this.MethodName,
|
MethodName = this.MethodName,
|
||||||
MethodAnotherName = this.MethodAnotherName,
|
MethodAnotherName = this.MethodAnotherName,
|
||||||
NodeType = this.MethodDynamicType.ToString(),
|
NodeType = this.MethodDynamicType.ToString(),
|
||||||
@@ -222,6 +232,7 @@ namespace Serein.Library
|
|||||||
// this => 是元数据
|
// this => 是元数据
|
||||||
var md = new MethodDetails( nodeModel) // 创建新节点时拷贝实例
|
var md = new MethodDetails( nodeModel) // 创建新节点时拷贝实例
|
||||||
{
|
{
|
||||||
|
AssemblyName = this.AssemblyName,
|
||||||
ActingInstance = this.ActingInstance,
|
ActingInstance = this.ActingInstance,
|
||||||
ActingInstanceType = this.ActingInstanceType,
|
ActingInstanceType = this.ActingInstanceType,
|
||||||
MethodDynamicType = this.MethodDynamicType,
|
MethodDynamicType = this.MethodDynamicType,
|
||||||
@@ -231,8 +242,9 @@ namespace Serein.Library
|
|||||||
MethodLockName = this.MethodLockName,
|
MethodLockName = this.MethodLockName,
|
||||||
IsProtectionParameter = this.IsProtectionParameter,
|
IsProtectionParameter = this.IsProtectionParameter,
|
||||||
ParamsArgIndex = this.ParamsArgIndex,
|
ParamsArgIndex = this.ParamsArgIndex,
|
||||||
|
ParameterDetailss = this.ParameterDetailss?.Select(p => p?.CloneOfModel(nodeModel)).ToArray(), // 拷贝属于节点方法的新入参描述
|
||||||
};
|
};
|
||||||
md.ParameterDetailss = this.ParameterDetailss?.Select(p => p?.CloneOfModel(nodeModel)).ToArray(); // 拷贝属于节点方法的新入参描述
|
|
||||||
return md;
|
return md;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ namespace Serein.Library
|
|||||||
return new NodeInfo
|
return new NodeInfo
|
||||||
{
|
{
|
||||||
Guid = Guid,
|
Guid = Guid,
|
||||||
|
AssemblyName = MethodDetails.AssemblyName,
|
||||||
MethodName = MethodDetails?.MethodName,
|
MethodName = MethodDetails?.MethodName,
|
||||||
Label = MethodDetails?.MethodAnotherName,
|
Label = MethodDetails?.MethodAnotherName,
|
||||||
Type = this.GetType().ToString(),
|
Type = this.GetType().ToString(),
|
||||||
@@ -316,7 +317,7 @@ namespace Serein.Library
|
|||||||
{
|
{
|
||||||
throw new Exception($"节点{this.Guid}不存在方法信息,请检查是否需要重写节点的ExecutingAsync");
|
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}不存在对应委托");
|
throw new Exception($"节点{this.Guid}不存在对应委托");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ namespace Serein.Library
|
|||||||
/// 依赖的DLL
|
/// 依赖的DLL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
public Library[] Librarys { get; set; }
|
public NodeLibraryInfo[] Librarys { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 起始节点GUID
|
/// 起始节点GUID
|
||||||
@@ -132,38 +132,63 @@ namespace Serein.Library
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 项目依赖的程序集,项目文件相关
|
/// 项目依赖的程序集,项目文件相关
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Library
|
/// <summary>
|
||||||
|
public class NodeLibraryInfo
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 文件名称
|
/// 文件名
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
public string FileName { get; set; }
|
public string FileName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 文件路径
|
/// 路径
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string FilePath { get; set; }
|
public string FilePath { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 程序集名称
|
/// 所属的程序集名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string AssemblyName { get; set; }
|
public string AssemblyName { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region 暂时注释
|
||||||
|
/*public class LibraryInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 文件名称
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
public string FileName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 文件路径
|
||||||
|
/// </summary>
|
||||||
|
public string FilePath { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 程序集名称
|
||||||
|
/// </summary>
|
||||||
|
public string AssemblyName { get; set; }
|
||||||
|
}*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点信息,项目文件相关
|
/// 节点信息,项目文件相关
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class NodeInfo
|
public class NodeInfo
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// GUID
|
/// 节点的GUID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
public string Guid { get; set; }
|
public string Guid { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 名称
|
/// 节点方法所属的程序集名称
|
||||||
|
/// </summary>
|
||||||
|
public string AssemblyName { get;set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 节点对应的名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
public string MethodName { get; set; }
|
public string MethodName { get; set; }
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using Serein.Library.Utils.SereinExpression;
|
|||||||
using Serein.NodeFlow.Model;
|
using Serein.NodeFlow.Model;
|
||||||
using Serein.NodeFlow.Tool;
|
using Serein.NodeFlow.Tool;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Metadata.Ecma335;
|
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 远程管理
|
#region 远程管理
|
||||||
@@ -227,14 +229,16 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 通过程序集名称管理动态加载的程序集,用于节点创建提供方法描述,流程运行时提供Emit委托
|
/// 通过程序集名称管理动态加载的程序集,用于节点创建提供方法描述,流程运行时提供Emit委托
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ConcurrentDictionary<string, FlowLibrary> FlowLibrarys { get; } = [];
|
private readonly FlowLibraryManagement FlowLibraryManagement;
|
||||||
|
|
||||||
|
#if false
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Library 与 MethodDetailss的依赖关系
|
/// Library 与 MethodDetailss的依赖关系
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ConcurrentDictionary<NodeLibraryInfo, List<MethodDetails>> MethodDetailsOfLibraryInfos { get; } = [];
|
public ConcurrentDictionary<NodeLibraryInfo, List<MethodDetails>> MethodDetailsOfLibraryInfos { get; } = [];
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>存储已加载的程序集</para>
|
/// <para>存储已加载的程序集</para>
|
||||||
/// <para>Key:程序集的FullName </para>
|
/// <para>Key:程序集的FullName </para>
|
||||||
@@ -259,6 +263,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// md.Methodname - delegate
|
/// md.Methodname - delegate
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private ConcurrentDictionary<string, DelegateDetails> MethodDelegates { get; } = [];
|
private ConcurrentDictionary<string, DelegateDetails> MethodDelegates { get; } = [];
|
||||||
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// IOC对象容器管理
|
/// IOC对象容器管理
|
||||||
@@ -351,17 +356,13 @@ namespace Serein.NodeFlow.Env
|
|||||||
flowStarter = new FlowStarter();
|
flowStarter = new FlowStarter();
|
||||||
var nodes = NodeModels.Values.ToList();
|
var nodes = NodeModels.Values.ToList();
|
||||||
|
|
||||||
List<MethodDetails> initMethods = [];
|
|
||||||
List<MethodDetails> loadMethods = [];
|
|
||||||
List<MethodDetails> 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);
|
|
||||||
|
|
||||||
initMethods.AddRange(initMds);
|
List<MethodDetails> initMethods = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Init);
|
||||||
loadMethods.AddRange(loadMds);
|
List<MethodDetails> loadMethods = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Loading);
|
||||||
exitMethods.AddRange(exitMds);
|
List<MethodDetails> exitMethods = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Exit);
|
||||||
|
Dictionary<RegisterSequence, List<Type>> autoRegisterTypes = this.FlowLibraryManagement.GetaAutoRegisterType();
|
||||||
|
|
||||||
|
|
||||||
IOC.Reset(); // 开始运行时清空ioc中注册的实例
|
IOC.Reset(); // 开始运行时清空ioc中注册的实例
|
||||||
|
|
||||||
@@ -369,7 +370,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
if (this.UIContextOperation is not null)
|
if (this.UIContextOperation is not null)
|
||||||
IOC.CustomRegisterInstance(typeof(UIContextOperation).FullName, this.UIContextOperation, false);
|
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)
|
if (FlipFlopState == RunState.Completion)
|
||||||
{
|
{
|
||||||
@@ -480,30 +481,9 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<FlowEnvInfo> GetEnvInfoAsync()
|
public async Task<FlowEnvInfo> GetEnvInfoAsync()
|
||||||
{
|
{
|
||||||
Dictionary<NodeLibraryInfo, List<MethodDetailsInfo>> MdsOfLibraryInfos = [];
|
// 获取所有的程序集对应的方法信息(程序集相关的数据)
|
||||||
|
var libraryMdss = this.FlowLibraryManagement.GetAllLibraryMds().ToArray();
|
||||||
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<MethodDetailsInfo>();
|
|
||||||
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 project = await GetProjectInfoAsync();
|
var project = await GetProjectInfoAsync();
|
||||||
Console.WriteLine("已将当前环境信息发送到远程客户端");
|
Console.WriteLine("已将当前环境信息发送到远程客户端");
|
||||||
return new FlowEnvInfo
|
return new FlowEnvInfo
|
||||||
@@ -540,13 +520,13 @@ namespace Serein.NodeFlow.Env
|
|||||||
foreach (var dllPath in dllPaths)
|
foreach (var dllPath in dllPaths)
|
||||||
{
|
{
|
||||||
var dllFilePath = Path.GetFullPath(Path.Combine(filePath, dllPath));
|
var dllFilePath = Path.GetFullPath(Path.Combine(filePath, dllPath));
|
||||||
LoadDllNodeInfo(dllFilePath);
|
LoadDll(dllFilePath); // 加载项目文件时加载对应的程序集
|
||||||
}
|
}
|
||||||
|
|
||||||
List<(NodeModelBase, string[])> regionChildNodes = new List<(NodeModelBase, string[])>();
|
List<(NodeModelBase, string[])> regionChildNodes = new List<(NodeModelBase, string[])>();
|
||||||
List<(NodeModelBase, PositionOfUI)> ordinaryNodes = new List<(NodeModelBase, PositionOfUI)>();
|
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);
|
var controlType = FlowFunc.GetNodeControlType(nodeInfo);
|
||||||
if (controlType == NodeControlType.None)
|
if (controlType == NodeControlType.None)
|
||||||
@@ -555,11 +535,14 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MethodDetails? methodDetails = null;
|
if (string.IsNullOrEmpty(nodeInfo.AssemblyName) && string.IsNullOrEmpty(nodeInfo.MethodName))
|
||||||
if (!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); // 加载项目时创建节点
|
var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载项目时创建节点
|
||||||
nodeModel.LoadInfo(nodeInfo); // 创建节点model
|
nodeModel.LoadInfo(nodeInfo); // 创建节点model
|
||||||
if (nodeModel is null)
|
if (nodeModel is null)
|
||||||
@@ -726,7 +709,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
{
|
{
|
||||||
var projectData = new SereinProjectData()
|
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(),
|
Nodes = NodeModels.Values.Select(node => node.ToInfo()).Where(info => info is not null).ToArray(),
|
||||||
StartNode = NodeModels.Values.FirstOrDefault(it => it.IsStart)?.Guid,
|
StartNode = NodeModels.Values.FirstOrDefault(it => it.IsStart)?.Guid,
|
||||||
};
|
};
|
||||||
@@ -739,10 +722,11 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dllPath"></param>
|
/// <param name="dllPath"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
// [AutoSocketHandle]
|
|
||||||
public void LoadDll(string dllPath)
|
public void LoadDll(string dllPath)
|
||||||
{
|
{
|
||||||
LoadDllNodeInfo(dllPath);
|
(var libraryInfo, var mdInfos) = FlowLibraryManagement.LoadLibrary(dllPath);
|
||||||
|
UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(libraryInfo, mdInfos))); // 通知UI创建dll面板显示
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -752,49 +736,51 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public bool RemoteDll(string assemblyName)
|
public bool RemoteDll(string assemblyName)
|
||||||
{
|
{
|
||||||
var library = LibraryInfos.Values.FirstOrDefault(nl => assemblyName.Equals(nl.AssemblyName));
|
return FlowLibraryManagement.UnloadLibrary(assemblyName);
|
||||||
if (library is null)
|
|
||||||
{
|
//var library = LibraryInfos.Values.FirstOrDefault(nl => assemblyName.Equals(nl.AssemblyName));
|
||||||
return false;
|
//if (library is null)
|
||||||
}
|
//{
|
||||||
var groupedNodes = NodeModels.Values
|
// return false;
|
||||||
.Where(node => node.MethodDetails is not null)
|
//}
|
||||||
.ToArray()
|
//var groupedNodes = NodeModels.Values
|
||||||
.GroupBy(node => node.MethodDetails?.MethodName)
|
// .Where(node => node.MethodDetails is not null)
|
||||||
.ToDictionary(
|
// .ToArray()
|
||||||
key => key.Key,
|
// .GroupBy(node => node.MethodDetails?.MethodName)
|
||||||
group => group.Count());
|
// .ToDictionary(
|
||||||
|
// key => key.Key,
|
||||||
|
// group => group.Count());
|
||||||
|
|
||||||
|
|
||||||
if (NodeModels.Count == 0)
|
//if (NodeModels.Count == 0)
|
||||||
{
|
//{
|
||||||
return true; // 当前无节点,可以直接删除
|
// return true; // 当前无节点,可以直接删除
|
||||||
}
|
//}
|
||||||
|
|
||||||
if (MethodDetailsOfLibraryInfos.TryGetValue(library, out var mds)) // 存在方法
|
//if (MethodDetailsOfLibraryInfos.TryGetValue(library, out var mds)) // 存在方法
|
||||||
{
|
//{
|
||||||
foreach (var md in mds)
|
// foreach (var md in mds)
|
||||||
{
|
// {
|
||||||
if (groupedNodes.TryGetValue(md.MethodName, out int count))
|
// if (groupedNodes.TryGetValue(md.MethodName, out int count))
|
||||||
{
|
// {
|
||||||
if (count > 0)
|
// if (count > 0)
|
||||||
{
|
// {
|
||||||
return false; // 创建过相关的节点,无法移除
|
// return false; // 创建过相关的节点,无法移除
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
// 开始移除相关信息
|
// // 开始移除相关信息
|
||||||
foreach (var md in mds)
|
// foreach (var md in mds)
|
||||||
{
|
// {
|
||||||
MethodDetailss.TryRemove(md.MethodName, out _);
|
// MethodDetailss.TryRemove(md.MethodName, out _);
|
||||||
}
|
// }
|
||||||
MethodDetailsOfLibraryInfos.TryRemove(library, out _);
|
// MethodDetailsOfLibraryInfos.TryRemove(library, out _);
|
||||||
return true;
|
// return true;
|
||||||
}
|
//}
|
||||||
else
|
//else
|
||||||
{
|
//{
|
||||||
return true;
|
// return true;
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -814,7 +800,9 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
else
|
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); // 一般的加载节点方法
|
nodeModel = FlowFunc.CreateNode(this, nodeControlType, methodDetails); // 一般的加载节点方法
|
||||||
}
|
}
|
||||||
@@ -1026,25 +1014,18 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// 获取方法描述
|
/// 获取方法描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
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)
|
mdInfo = null;
|
||||||
{
|
|
||||||
md = t_md.ToInfo();
|
|
||||||
if (md != null)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
md = null;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
md = null;
|
mdInfo = md?.ToInfo();
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1058,18 +1039,9 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <param name="methodName"></param>
|
/// <param name="methodName"></param>
|
||||||
/// <param name="delegateDetails"></param>
|
/// <param name="delegateDetails"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public bool TryGetDelegateDetails(string methodName, out DelegateDetails? delegateDetails)
|
public bool TryGetDelegateDetails(string assemblyName, string methodName, out DelegateDetails? delegateDetails)
|
||||||
{
|
{
|
||||||
|
return FlowLibraryManagement.TryGetDelegateDetails(assemblyName, methodName, out delegateDetails);
|
||||||
if (!string.IsNullOrEmpty(methodName) && MethodDelegates.TryGetValue(methodName, out delegateDetails))
|
|
||||||
{
|
|
||||||
return delegateDetails != null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
delegateDetails = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1399,6 +1371,8 @@ namespace Serein.NodeFlow.Env
|
|||||||
|
|
||||||
#region 私有方法
|
#region 私有方法
|
||||||
|
|
||||||
|
#region 暂时注释
|
||||||
|
/*
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载指定路径的DLL文件
|
/// 加载指定路径的DLL文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1455,7 +1429,8 @@ namespace Serein.NodeFlow.Env
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移除连接关系
|
/// 移除连接关系
|
||||||
@@ -1507,7 +1482,8 @@ namespace Serein.NodeFlow.Env
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
#region 暂时注释
|
||||||
|
/*/// <summary>
|
||||||
/// 动态加载程序集
|
/// 动态加载程序集
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="assembly">程序集本身</param>
|
/// <param name="assembly">程序集本身</param>
|
||||||
@@ -1597,7 +1573,8 @@ namespace Serein.NodeFlow.Env
|
|||||||
Console.WriteLine(ex.ToString());
|
Console.WriteLine(ex.ToString());
|
||||||
return ([], []);
|
return ([], []);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建节点
|
/// 创建节点
|
||||||
|
|||||||
@@ -390,14 +390,14 @@ namespace Serein.NodeFlow.Env
|
|||||||
currentFlowEnvironment.TriggerInterrupt(nodeGuid, expression, type);
|
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)
|
public void WriteLineObjToJson(object obj)
|
||||||
|
|||||||
@@ -89,13 +89,11 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="libraryInfo"></param>
|
/// <param name="libraryInfo"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
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 NodeLibraryInfo
|
||||||
return new Library.Library
|
|
||||||
{
|
{
|
||||||
AssemblyName = libraryInfo.AssemblyName,
|
AssemblyName = libraryInfo.AssemblyName,
|
||||||
//AssemblyName = library.Assembly.GetName().Name,
|
|
||||||
FileName = libraryInfo.FileName,
|
FileName = libraryInfo.FileName,
|
||||||
FilePath = libraryInfo.FilePath,
|
FilePath = libraryInfo.FilePath,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
{
|
{
|
||||||
AssemblyName = lib.AssemblyName,
|
AssemblyName = lib.AssemblyName,
|
||||||
FilePath = "Remote",
|
FilePath = "Remote",
|
||||||
|
FileName = "Remote",
|
||||||
};
|
};
|
||||||
var mdInfos = lib.Mds.ToList();
|
var mdInfos = lib.Mds.ToList();
|
||||||
UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibraryInfo, mdInfos))); // 通知UI创建dll面板显示
|
UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibraryInfo, mdInfos))); // 通知UI创建dll面板显示
|
||||||
@@ -791,14 +792,14 @@ namespace Serein.NodeFlow.Env
|
|||||||
return ChannelFlowInterrupt.CancelType.Error;
|
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");
|
Console.WriteLine("远程环境尚未实现的接口:TryGetMethodDetailsInfo");
|
||||||
mdInfo = null;
|
mdInfo = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetDelegateDetails(string methodName, out DelegateDetails del)
|
public bool TryGetDelegateDetails(string libraryName, string methodName, out DelegateDetails del)
|
||||||
{
|
{
|
||||||
Console.WriteLine("远程环境尚未实现的接口:TryGetDelegateDetails");
|
Console.WriteLine("远程环境尚未实现的接口:TryGetDelegateDetails");
|
||||||
del = null;
|
del = null;
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ namespace Serein.NodeFlow
|
|||||||
//object?[]? args = [Context];
|
//object?[]? args = [Context];
|
||||||
foreach (var md in initMethods) // 初始化
|
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("不存在对应委托");
|
throw new Exception("不存在对应委托");
|
||||||
}
|
}
|
||||||
@@ -205,7 +205,7 @@ namespace Serein.NodeFlow
|
|||||||
{
|
{
|
||||||
//object?[]? data = [md.ActingInstance, args];
|
//object?[]? data = [md.ActingInstance, args];
|
||||||
//md.MethodDelegate.DynamicInvoke(data);
|
//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("不存在对应委托");
|
throw new Exception("不存在对应委托");
|
||||||
}
|
}
|
||||||
@@ -228,7 +228,7 @@ namespace Serein.NodeFlow
|
|||||||
|
|
||||||
foreach (MethodDetails? md in exitMethods)
|
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("不存在对应委托");
|
throw new Exception("不存在对应委托");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,7 +111,8 @@ namespace Serein.NodeFlow.Model
|
|||||||
return new NodeInfo
|
return new NodeInfo
|
||||||
{
|
{
|
||||||
Guid = Guid,
|
Guid = Guid,
|
||||||
MethodName = MethodDetails?.MethodName,
|
AssemblyName = MethodDetails.AssemblyName,
|
||||||
|
MethodName = MethodDetails.MethodName,
|
||||||
Label = MethodDetails?.MethodAnotherName,
|
Label = MethodDetails?.MethodAnotherName,
|
||||||
Type = this.GetType().ToString(),
|
Type = this.GetType().ToString(),
|
||||||
TrueNodes = trueNodes.ToArray(),
|
TrueNodes = trueNodes.ToArray(),
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
MethodDetails md = MethodDetails;
|
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("不存在对应委托");
|
throw new Exception("不存在对应委托");
|
||||||
}
|
}
|
||||||
|
|||||||
230
NodeFlow/Tool/FlowLibrary.cs
Normal file
230
NodeFlow/Tool/FlowLibrary.cs
Normal file
@@ -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
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
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();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 加载程序集时创建的方法描述
|
||||||
|
/// </summary>
|
||||||
|
public ConcurrentDictionary<string, MethodDetails> MethodDetailss { get; } = new ConcurrentDictionary<string, MethodDetails>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 管理通过Emit动态构建的委托
|
||||||
|
/// </summary>
|
||||||
|
public ConcurrentDictionary<string, DelegateDetails> DelegateDetailss { get; } = new ConcurrentDictionary<string, DelegateDetails>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 记录不同的注册时机需要自动创建全局唯一实例的类型信息
|
||||||
|
/// </summary>
|
||||||
|
public ConcurrentDictionary<RegisterSequence, List<Type>> RegisterTypes { get; } = new ConcurrentDictionary<RegisterSequence, List<Type>>();
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 卸载当前程序集以及附带的所有信息
|
||||||
|
/// </summary>
|
||||||
|
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<Type>();
|
||||||
|
// RegisterTypes.TryAdd(kv.Key, types);
|
||||||
|
// }
|
||||||
|
// types.AddRange(kv.Value);
|
||||||
|
// }
|
||||||
|
// var mdInfos = mdlist.Select(md => md.ToInfo()).ToList(); // 转换成方法信息
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 动态加载程序集
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assembly">程序集本身</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private bool LoadAssembly(Assembly assembly)
|
||||||
|
{
|
||||||
|
#region 检查入参
|
||||||
|
|
||||||
|
// 加载DLL,创建 MethodDetails、实例作用对象、委托方法
|
||||||
|
var assemblyName = assembly.GetName().Name;
|
||||||
|
if (string.IsNullOrEmpty(assemblyName)) // 防止动态程序集没有定义程序集名称
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Type> 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<DynamicFlowAttribute>() 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<AutoRegisterAttribute>() is AutoRegisterAttribute attribute)
|
||||||
|
{
|
||||||
|
if (!RegisterTypes.TryGetValue(attribute.Class, out var valus))
|
||||||
|
{
|
||||||
|
valus = new List<Type>();
|
||||||
|
RegisterTypes.TryAdd(attribute.Class, valus);
|
||||||
|
}
|
||||||
|
valus.Add(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.ToString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 管理加载在流程的程序集
|
|
||||||
/// </summary>
|
|
||||||
public class FlowLibraryLoader : AssemblyLoadContext
|
|
||||||
{
|
|
||||||
private Assembly _pluginAssembly;
|
|
||||||
|
|
||||||
public string FullName => _pluginAssembly.FullName;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 加载程序集
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pluginPath"></param>
|
|
||||||
public FlowLibraryLoader(string pluginPath) : base(isCollectible: true)
|
|
||||||
{
|
|
||||||
_pluginAssembly = LoadFromAssemblyPath(pluginPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 保持默认加载行为
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="assemblyName"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
|
|
||||||
protected override Assembly Load(AssemblyName assemblyName)
|
|
||||||
{
|
|
||||||
return null; // 保持默认加载行为
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public List<Type> LoadFlowTypes()
|
|
||||||
{
|
|
||||||
return _pluginAssembly.GetTypes().ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否对程序集的引用
|
|
||||||
/// </summary>
|
|
||||||
public void UnloadPlugin()
|
|
||||||
{
|
|
||||||
_pluginAssembly = null; // 释放对程序集的引用
|
|
||||||
Unload(); // 触发卸载
|
|
||||||
// 强制进行垃圾回收,以便完成卸载
|
|
||||||
GC.Collect();
|
|
||||||
GC.WaitForPendingFinalizers();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
264
NodeFlow/Tool/FlowLibraryManagement.cs
Normal file
264
NodeFlow/Tool/FlowLibraryManagement.cs
Normal file
@@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 管理加载在运行环境中的外部程序集
|
||||||
|
/// </summary>
|
||||||
|
public class FlowLibraryManagement
|
||||||
|
{
|
||||||
|
public FlowLibraryManagement(IFlowEnvironment flowEnvironment)
|
||||||
|
{
|
||||||
|
this.flowEnvironment = flowEnvironment;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly IFlowEnvironment flowEnvironment;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存所有加载了的程序集
|
||||||
|
/// </summary>
|
||||||
|
private ConcurrentDictionary<string, FlowLibrary> _myFlowLibrarys = new ConcurrentDictionary<string, FlowLibrary>();
|
||||||
|
|
||||||
|
public (NodeLibraryInfo,List<MethodDetailsInfo>) 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取方法描述
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assemblyName">程序集名称</param>
|
||||||
|
/// <param name="methodName">方法名称</param>
|
||||||
|
/// <param name="md">返回的方法描述</param>
|
||||||
|
/// <returns>是否获取成功</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取方法调用的委托
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assemblyName">程序集名称</param>
|
||||||
|
/// <param name="methodName">方法名称</param>
|
||||||
|
/// <param name="dd">返回的委托调用封装类</param>
|
||||||
|
/// <returns>是否获取成功</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取(初始化/加载时/退出后)相应的节点方法
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodeType"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public List<MethodDetails> GetMdsOnFlowStart(NodeType nodeType)
|
||||||
|
{
|
||||||
|
List<MethodDetails> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取流程启动时在不同时间点需要自动实例化的类型
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Dictionary<RegisterSequence, List<Type>> GetaAutoRegisterType()
|
||||||
|
{
|
||||||
|
Dictionary<RegisterSequence, List<Type>> rsTypes = new Dictionary<RegisterSequence, List<Type>>();
|
||||||
|
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<Type>();
|
||||||
|
rsTypes.Add(@class, tmpTypes);
|
||||||
|
}
|
||||||
|
tmpTypes.AddRange(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rsTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取所有方法信息,用于保存项目时调用
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public List<LibraryMds> GetAllLibraryMds()
|
||||||
|
{
|
||||||
|
List<LibraryMds> mds = new List<LibraryMds>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 序列化当前项目的依赖信息、节点信息,用于远程登录的场景,需要将依赖信息从本地(受控端)发送到远程(主控端)
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public List<NodeLibraryInfo> GetAllLibraryInfo()
|
||||||
|
{
|
||||||
|
return _myFlowLibrarys.Values.Select(library => library.ToInfo()).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#region 功能性方法
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从文件路径中加载程序集,返回相应的信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dllPath"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private (NodeLibraryInfo, List<MethodDetailsInfo>) 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<MethodDetailsInfo>) 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///// <summary>
|
||||||
|
///// 是否对程序集的引用
|
||||||
|
///// </summary>
|
||||||
|
//public void UnloadPlugin()
|
||||||
|
//{
|
||||||
|
// _pluginAssembly = null; // 释放对程序集的引用
|
||||||
|
// Unload(); // 触发卸载
|
||||||
|
// // 强制进行垃圾回收,以便完成卸载
|
||||||
|
// GC.Collect();
|
||||||
|
// GC.WaitForPendingFinalizers();
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ using System.Collections.Concurrent;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Serein.Library.FlowNode;
|
using Serein.Library.FlowNode;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Tool;
|
namespace Serein.NodeFlow.Tool;
|
||||||
|
|
||||||
@@ -21,21 +22,35 @@ public static class NodeMethodDetailsHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建方法信息
|
/// 创建方法信息/委托信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <param name="type">方法所属的类型</param>
|
||||||
public static (MethodDetails?, DelegateDetails?) CreateMethodDetails(Type type, MethodInfo method, string assemblyName)
|
/// <param name="methodInfo">方法信息</param>
|
||||||
|
/// <param name="assemblyName">方法所属的程序集名称</param>
|
||||||
|
/// <param name="methodDetails">创建的方法描述,用来生成节点信息</param>
|
||||||
|
/// <param name="delegateDetails">方法对应的Emit动态委托</param>
|
||||||
|
/// <returns>指示是否创建成功</returns>
|
||||||
|
public static bool TryCreateDetails(Type type,
|
||||||
|
MethodInfo methodInfo,
|
||||||
|
string assemblyName,
|
||||||
|
[MaybeNullWhen(false)] out MethodDetails methodDetails,
|
||||||
|
[MaybeNullWhen(false)] out DelegateDetails delegateDetails)
|
||||||
{
|
{
|
||||||
var attribute = method.GetCustomAttribute<NodeActionAttribute>();
|
|
||||||
|
|
||||||
|
var attribute = methodInfo.GetCustomAttribute<NodeActionAttribute>();
|
||||||
if(attribute is null || attribute.Scan == false)
|
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}";
|
var methodName = $"{assemblyName}.{type.Name}.{methodInfo.Name}";
|
||||||
Console.WriteLine("loading method : " +dllTypeMethodName);
|
Console.WriteLine("loading method : " + methodName);
|
||||||
Debug.WriteLine("loading method : " +dllTypeMethodName);
|
|
||||||
var explicitDataOfParameters = GetExplicitDataOfParameters(method.GetParameters());
|
// 创建参数信息
|
||||||
|
var explicitDataOfParameters = GetExplicitDataOfParameters(methodInfo.GetParameters());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -46,17 +61,17 @@ public static class NodeMethodDetailsHelper
|
|||||||
// method.ReturnType);// 返回值
|
// method.ReturnType);// 返回值
|
||||||
|
|
||||||
//// 通过表达式树生成委托
|
//// 通过表达式树生成委托
|
||||||
var emitMethodType = EmitHelper.CreateDynamicMethod(method, out var methodDelegate);// 返回值
|
var emitMethodType = EmitHelper.CreateDynamicMethod(methodInfo, out var methodDelegate);// 返回值
|
||||||
|
|
||||||
Type? returnType;
|
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 (attribute.MethodDynamicType == Library.NodeType.Flipflop)
|
||||||
{
|
{
|
||||||
if (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
|
if (methodInfo.ReturnType.IsGenericType && methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
|
||||||
{
|
{
|
||||||
// 获取 Task<> 的泛型参数类型
|
// 获取 Task<> 的泛型参数类型
|
||||||
var innerType = method.ReturnType.GetGenericArguments()[0];
|
var innerType = methodInfo.ReturnType.GetGenericArguments()[0];
|
||||||
if (innerType.IsGenericType && innerType.GetGenericTypeDefinition() == typeof(IFlipflopContext<>))
|
if (innerType.IsGenericType && innerType.GetGenericTypeDefinition() == typeof(IFlipflopContext<>))
|
||||||
{
|
{
|
||||||
var flipflopType = innerType.GetGenericArguments()[0];
|
var flipflopType = innerType.GetGenericArguments()[0];
|
||||||
@@ -64,14 +79,18 @@ public static class NodeMethodDetailsHelper
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine($"[{dllTypeMethodName}]跳过创建,返回类型非预期的Task<IFlipflopContext<TResult>>。");
|
Console.WriteLine($"[{methodName}]跳过创建,返回类型非预期的Task<IFlipflopContext<TResult>>。");
|
||||||
return (null, null);
|
methodDetails = null;
|
||||||
|
delegateDetails = null;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine($"[{dllTypeMethodName}]跳过创建,因为触发器方法的返回值并非Task<>,将无法等待。");
|
Console.WriteLine($"[{methodName}]跳过创建,因为触发器方法的返回值并非Task<>,将无法等待。");
|
||||||
return (null, null);
|
methodDetails = null;
|
||||||
|
delegateDetails = null;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (!isTask || taskResult != typeof(IFlipflopContext<object>))
|
//if (!isTask || taskResult != typeof(IFlipflopContext<object>))
|
||||||
@@ -86,11 +105,11 @@ public static class NodeMethodDetailsHelper
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
returnType = method.ReturnType;
|
returnType = methodInfo.ReturnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(attribute.AnotherName)){
|
if (string.IsNullOrEmpty(attribute.AnotherName)){
|
||||||
attribute.AnotherName = method.Name;
|
attribute.AnotherName = methodInfo.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -108,17 +127,21 @@ public static class NodeMethodDetailsHelper
|
|||||||
{
|
{
|
||||||
ActingInstanceType = type,
|
ActingInstanceType = type,
|
||||||
// ActingInstance = instance,
|
// ActingInstance = instance,
|
||||||
MethodName = dllTypeMethodName,
|
MethodName = methodName,
|
||||||
|
AssemblyName = assemblyName,
|
||||||
MethodDynamicType = attribute.MethodDynamicType,
|
MethodDynamicType = attribute.MethodDynamicType,
|
||||||
MethodLockName = attribute.LockName,
|
MethodLockName = attribute.LockName,
|
||||||
MethodAnotherName = methodMethodAnotherName,
|
MethodAnotherName = methodMethodAnotherName,
|
||||||
ParameterDetailss = explicitDataOfParameters,
|
ParameterDetailss = explicitDataOfParameters,
|
||||||
ReturnType = returnType,
|
ReturnType = returnType,
|
||||||
// 如果存在可变参数,取最后一个元素的下标,否则为-1;
|
// 如果存在可变参数,取最后一个元素的下标,否则为-1;
|
||||||
ParamsArgIndex = hasParamsArg ? explicitDataOfParameters.Length-1 : -1,
|
ParamsArgIndex = hasParamsArg ? explicitDataOfParameters.Length - 1 : -1,
|
||||||
};
|
};
|
||||||
var dd = new DelegateDetails(emitMethodType, methodDelegate) ;
|
var dd = new DelegateDetails(emitMethodType, methodDelegate) ;
|
||||||
return (md, dd);
|
|
||||||
|
methodDetails = md;
|
||||||
|
delegateDetails = dd;
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2505,7 +2505,7 @@ namespace Serein.Workbench
|
|||||||
Console.WriteLine(savePath);
|
Console.WriteLine(savePath);
|
||||||
for (int index = 0; index < projectData.Librarys.Length; index++)
|
for (int index = 0; index < projectData.Librarys.Length; index++)
|
||||||
{
|
{
|
||||||
Library.Library? library = projectData.Librarys[index];
|
NodeLibraryInfo? library = projectData.Librarys[index];
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string targetPath = System.IO.Path.Combine(librarySavePath, library.FileName); // 目标文件夹
|
string targetPath = System.IO.Path.Combine(librarySavePath, library.FileName); // 目标文件夹
|
||||||
|
|||||||
Reference in New Issue
Block a user