mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-02 15:50:47 +08:00
优化了运行环境与启动器的运行逻辑,以及IOC容器的注册/绑定/获取对象的机制
This commit is contained in:
@@ -9,7 +9,7 @@ namespace Serein.Library.Core.NodeFlow
|
||||
/// </summary>
|
||||
public class DynamicContext: IDynamicContext
|
||||
{
|
||||
public DynamicContext(ISereinIoc sereinIoc, IFlowEnvironment flowEnvironment)
|
||||
public DynamicContext(ISereinIOC sereinIoc, IFlowEnvironment flowEnvironment)
|
||||
{
|
||||
SereinIoc = sereinIoc;
|
||||
FlowEnvironment = flowEnvironment;
|
||||
@@ -17,7 +17,7 @@ namespace Serein.Library.Core.NodeFlow
|
||||
}
|
||||
|
||||
public NodeRunCts NodeRunCts { get; set; }
|
||||
public ISereinIoc SereinIoc { get; }
|
||||
public ISereinIOC SereinIoc { get; }
|
||||
public IFlowEnvironment FlowEnvironment { get; }
|
||||
|
||||
public Task CreateTimingTask(Action action, int time = 100, int count = -1)
|
||||
|
||||
@@ -12,13 +12,13 @@ namespace Serein.Library.Framework.NodeFlow
|
||||
/// </summary>
|
||||
public class DynamicContext : IDynamicContext
|
||||
{
|
||||
public DynamicContext(ISereinIoc sereinIoc, IFlowEnvironment flowEnvironment)
|
||||
public DynamicContext(ISereinIOC sereinIoc, IFlowEnvironment flowEnvironment)
|
||||
{
|
||||
SereinIoc = sereinIoc;
|
||||
FlowEnvironment = flowEnvironment;
|
||||
}
|
||||
public NodeRunCts NodeRunCts { get; set; }
|
||||
public ISereinIoc SereinIoc { get; }
|
||||
public ISereinIOC SereinIoc { get; }
|
||||
public IFlowEnvironment FlowEnvironment { get; }
|
||||
public Task CreateTimingTask(Action action, int time = 100, int count = -1)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Serein.Library.Api
|
||||
public interface IDynamicContext
|
||||
{
|
||||
IFlowEnvironment FlowEnvironment { get; }
|
||||
ISereinIoc SereinIoc { get; }
|
||||
ISereinIOC SereinIoc { get; }
|
||||
NodeRunCts NodeRunCts { get; set; }
|
||||
Task CreateTimingTask(Action action, int time = 100, int count = -1);
|
||||
}
|
||||
|
||||
@@ -7,48 +7,22 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Api
|
||||
{
|
||||
|
||||
public class FlowEventArgs : EventArgs
|
||||
{
|
||||
public bool IsSucceed { get; protected set; } = true;
|
||||
public string ErrorTips { get; protected set; } = string.Empty;
|
||||
}
|
||||
|
||||
|
||||
#region 环境委托
|
||||
/// <summary>
|
||||
/// 流程运行完成
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public delegate void FlowRunCompleteHandler(FlowEventArgs eventArgs);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 加载节点
|
||||
/// 加载项目文件时成功加载了节点
|
||||
/// </summary>
|
||||
public delegate void LoadNodeHandler(LoadNodeEventArgs eventArgs);
|
||||
public class LoadNodeEventArgs : FlowEventArgs
|
||||
{
|
||||
public LoadNodeEventArgs(NodeInfo NodeInfo, MethodDetails MethodDetailss)
|
||||
{
|
||||
this.NodeInfo = NodeInfo;
|
||||
this.MethodDetailss = MethodDetailss;
|
||||
}
|
||||
public NodeInfo NodeInfo { get; protected set; }
|
||||
public MethodDetails MethodDetailss { get; protected set; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 加载DLL
|
||||
/// 加载项目文件时成功加载了DLL文件
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
public delegate void LoadDLLHandler(LoadDLLEventArgs eventArgs);
|
||||
public class LoadDLLEventArgs : FlowEventArgs
|
||||
{
|
||||
public LoadDLLEventArgs(Assembly Assembly, List<MethodDetails> MethodDetailss)
|
||||
{
|
||||
this.Assembly = Assembly;
|
||||
this.MethodDetailss = MethodDetailss;
|
||||
}
|
||||
public Assembly Assembly { get; protected set; }
|
||||
public List<MethodDetails> MethodDetailss { get; protected set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运行环境节点连接发生了改变
|
||||
@@ -57,43 +31,132 @@ namespace Serein.Library.Api
|
||||
/// <param name="toNodeGuid"></param>
|
||||
/// <param name="connectionType"></param>
|
||||
public delegate void NodeConnectChangeHandler(NodeConnectChangeEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 环境中加载了一个节点
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid"></param>
|
||||
/// <param name="toNodeGuid"></param>
|
||||
/// <param name="connectionType"></param>
|
||||
public delegate void NodeCreateHandler(NodeCreateEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 环境中流程起始节点发生了改变
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public delegate void StartNodeChangeHandler(StartNodeChangeEventArgs eventArgs);
|
||||
#endregion
|
||||
|
||||
#region 环境事件签名
|
||||
|
||||
/// <summary>
|
||||
/// 流程事件签名基类
|
||||
/// </summary>
|
||||
public class FlowEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否完成
|
||||
/// </summary>
|
||||
public bool IsSucceed { get; protected set; } = true;
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
public string ErrorTips { get; protected set; } = string.Empty;
|
||||
}
|
||||
public class LoadNodeEventArgs : FlowEventArgs
|
||||
{
|
||||
public LoadNodeEventArgs(NodeInfo NodeInfo, MethodDetails MethodDetailss)
|
||||
{
|
||||
this.NodeInfo = NodeInfo;
|
||||
this.MethodDetailss = MethodDetailss;
|
||||
}
|
||||
/// <summary>
|
||||
/// 项目文件节点信息参数
|
||||
/// </summary>
|
||||
public NodeInfo NodeInfo { get; protected set; }
|
||||
/// <summary>
|
||||
/// 已加载在环境中的方法描述
|
||||
/// </summary>
|
||||
public MethodDetails MethodDetailss { get; protected set; }
|
||||
}
|
||||
|
||||
|
||||
public class LoadDLLEventArgs : FlowEventArgs
|
||||
{
|
||||
public LoadDLLEventArgs(Assembly Assembly, List<MethodDetails> MethodDetailss)
|
||||
{
|
||||
this.Assembly = Assembly;
|
||||
this.MethodDetailss = MethodDetailss;
|
||||
}
|
||||
/// <summary>
|
||||
/// 已加载了的程序集
|
||||
/// </summary>
|
||||
public Assembly Assembly { get; protected set; }
|
||||
/// <summary>
|
||||
/// dll文件中有效的流程方法描述
|
||||
/// </summary>
|
||||
public List<MethodDetails> MethodDetailss { get; protected set; }
|
||||
}
|
||||
|
||||
|
||||
public class NodeConnectChangeEventArgs : FlowEventArgs
|
||||
{
|
||||
public enum ChangeTypeEnum
|
||||
/// <summary>
|
||||
/// 连接关系改变类型
|
||||
/// </summary>
|
||||
public enum ConnectChangeType
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建
|
||||
/// </summary>
|
||||
Create,
|
||||
/// <summary>
|
||||
/// 移除
|
||||
/// </summary>
|
||||
Remote,
|
||||
}
|
||||
public NodeConnectChangeEventArgs(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType, ChangeTypeEnum changeType)
|
||||
public NodeConnectChangeEventArgs(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType, ConnectChangeType changeType)
|
||||
{
|
||||
this.FromNodeGuid = fromNodeGuid;
|
||||
this.ToNodeGuid = toNodeGuid;
|
||||
this.ConnectionType = connectionType;
|
||||
this.ChangeType = changeType;
|
||||
}
|
||||
/// <summary>
|
||||
/// 连接关系中始节点的Guid
|
||||
/// </summary>
|
||||
public string FromNodeGuid { get; protected set; }
|
||||
/// <summary>
|
||||
/// 连接关系中目标节点的Guid
|
||||
/// </summary>
|
||||
public string ToNodeGuid { get; protected set; }
|
||||
/// <summary>
|
||||
/// 连接类型
|
||||
/// </summary>
|
||||
public ConnectionType ConnectionType { get; protected set; }
|
||||
public ChangeTypeEnum ChangeType { get; protected set; }
|
||||
/// <summary>
|
||||
/// 表示此次需要在两个节点之间创建连接关系,或是移除连接关系
|
||||
/// </summary>
|
||||
public ConnectChangeType ChangeType { get; protected set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加了节点
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid"></param>
|
||||
/// <param name="toNodeGuid"></param>
|
||||
/// <param name="connectionType"></param>
|
||||
public delegate void NodeCreateHandler(NodeCreateEventArgs eventArgs);
|
||||
|
||||
public class NodeCreateEventArgs : FlowEventArgs
|
||||
{
|
||||
public NodeCreateEventArgs(object nodeModel)
|
||||
{
|
||||
this.NodeModel = nodeModel;
|
||||
}
|
||||
/// <summary>
|
||||
/// 节点Model对象,目前需要手动转换对应的类型
|
||||
/// </summary>
|
||||
public object NodeModel { get; private set; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 环境中移除了一个节点
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
|
||||
public delegate void NodeRemoteHandler(NodeRemoteEventArgs eventArgs);
|
||||
public class NodeRemoteEventArgs : FlowEventArgs
|
||||
@@ -102,24 +165,32 @@ namespace Serein.Library.Api
|
||||
{
|
||||
this.NodeGuid = nodeGuid;
|
||||
}
|
||||
/// <summary>
|
||||
/// 被移除节点的Guid
|
||||
/// </summary>
|
||||
public string NodeGuid { get; private set; }
|
||||
}
|
||||
|
||||
|
||||
public delegate void StartNodeChangeHandler(StartNodeChangeEventArgs eventArgs);
|
||||
|
||||
|
||||
public class StartNodeChangeEventArgs: FlowEventArgs
|
||||
public class StartNodeChangeEventArgs : FlowEventArgs
|
||||
{
|
||||
public StartNodeChangeEventArgs(string oldNodeGuid, string newNodeGuid)
|
||||
{
|
||||
this.OldNodeGuid = oldNodeGuid;
|
||||
this.NewNodeGuid = newNodeGuid; ;
|
||||
}
|
||||
public string OldNodeGuid { get; private set; }
|
||||
public string NewNodeGuid { get; private set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 原来的起始节点Guid
|
||||
/// </summary>
|
||||
public string OldNodeGuid { get; private set; }
|
||||
/// <summary>
|
||||
/// 新的起始节点Guid
|
||||
/// </summary>
|
||||
public string NewNodeGuid { get; private set; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
public interface IFlowEnvironment
|
||||
{
|
||||
|
||||
@@ -4,24 +4,19 @@ using System.Text;
|
||||
|
||||
namespace Serein.Library.Api
|
||||
{
|
||||
public interface ISereinIoc
|
||||
public interface ISereinIOC
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或创建类型的实例(不注入依赖项)
|
||||
/// </summary>
|
||||
object GetOrCreateServiceInstance(Type serviceType, params object[] parameters);
|
||||
T GetOrCreateServiceInstance<T>(params object[] parameters);
|
||||
/// <summary>
|
||||
/// 清空
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ISereinIoc Reset();
|
||||
ISereinIOC Reset();
|
||||
/// <summary>
|
||||
/// 注册实例
|
||||
/// </summary>
|
||||
ISereinIoc Register(Type type, params object[] parameters);
|
||||
ISereinIoc Register<T>(params object[] parameters);
|
||||
ISereinIoc Register<TService, TImplementation>(params object[] parameters) where TImplementation : TService;
|
||||
ISereinIOC Register(Type type, params object[] parameters);
|
||||
ISereinIOC Register<T>(params object[] parameters);
|
||||
ISereinIOC Register<TService, TImplementation>(params object[] parameters) where TImplementation : TService;
|
||||
/// <summary>
|
||||
/// 获取或创建并注入目标类型
|
||||
/// </summary>
|
||||
@@ -35,15 +30,15 @@ namespace Serein.Library.Api
|
||||
/// 创建目标类型的对象, 并注入依赖项
|
||||
/// </summary>
|
||||
object Instantiate(Type type, params object[] parameters);
|
||||
ISereinIoc Build();
|
||||
ISereinIoc Run<T>(Action<T> action);
|
||||
ISereinIoc Run<T1, T2>(Action<T1, T2> action);
|
||||
ISereinIoc Run<T1, T2, T3>(Action<T1, T2, T3> action);
|
||||
ISereinIoc Run<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action);
|
||||
ISereinIoc Run<T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> action);
|
||||
ISereinIoc Run<T1, T2, T3, T4, T5, T6>(Action<T1, T2, T3, T4, T5, T6> action);
|
||||
ISereinIoc Run<T1, T2, T3, T4, T5, T6, T7>(Action<T1, T2, T3, T4, T5, T6, T7> action);
|
||||
ISereinIoc Run<T1, T2, T3, T4, T5, T6, T7, T8>(Action<T1, T2, T3, T4, T5, T6, T7, T8> action);
|
||||
ISereinIOC Build();
|
||||
ISereinIOC Run<T>(Action<T> action);
|
||||
ISereinIOC Run<T1, T2>(Action<T1, T2> action);
|
||||
ISereinIOC Run<T1, T2, T3>(Action<T1, T2, T3> action);
|
||||
ISereinIOC Run<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action);
|
||||
ISereinIOC Run<T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> action);
|
||||
ISereinIOC Run<T1, T2, T3, T4, T5, T6>(Action<T1, T2, T3, T4, T5, T6> action);
|
||||
ISereinIOC Run<T1, T2, T3, T4, T5, T6, T7>(Action<T1, T2, T3, T4, T5, T6, T7> action);
|
||||
ISereinIOC Run<T1, T2, T3, T4, T5, T6, T7, T8>(Action<T1, T2, T3, T4, T5, T6, T7, T8> action);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Serein.Library.Utils
|
||||
/// <summary>
|
||||
/// IOC管理容器
|
||||
/// </summary>
|
||||
public class SereinIoc : ISereinIoc
|
||||
public class SereinIOC : ISereinIOC
|
||||
{
|
||||
/// <summary>
|
||||
/// 实例集合
|
||||
@@ -33,78 +33,31 @@ namespace Serein.Library.Utils
|
||||
/// </summary>
|
||||
private readonly List<Type> _waitingForInstantiation;
|
||||
|
||||
public SereinIoc()
|
||||
public SereinIOC()
|
||||
{
|
||||
// 首先注册自己
|
||||
_dependencies = new ConcurrentDictionary<string, object>
|
||||
{
|
||||
[typeof(ISereinIoc).FullName] = this
|
||||
[typeof(ISereinIOC).FullName] = this
|
||||
};
|
||||
_typeMappings = new ConcurrentDictionary<string, Type>
|
||||
{
|
||||
[typeof(ISereinIoc).FullName] = typeof(ISereinIoc)
|
||||
[typeof(ISereinIOC).FullName] = typeof(ISereinIOC)
|
||||
};
|
||||
_unfinishedDependencies = new ConcurrentDictionary<string, List<(object, PropertyInfo)>>();
|
||||
_waitingForInstantiation = new List<Type>();
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取或创建实例对象(不注入对象的依赖项)
|
||||
/// </summary>
|
||||
/// <param name="type">目标类型</param>
|
||||
/// <param name="parameters">构造函数的参数</param>
|
||||
/// <returns></returns>
|
||||
public object GetOrCreateServiceInstance(Type type, params object[] parameters)
|
||||
{
|
||||
if (_dependencies.ContainsKey(type.FullName))
|
||||
{
|
||||
return _dependencies[type.FullName];
|
||||
}
|
||||
else
|
||||
{
|
||||
var instance = Activator.CreateInstance(type); // 创建目标类型的实例对象
|
||||
InjectDependencies(instance);// 注入目标对象的依赖项
|
||||
_dependencies[type.FullName] = instance; // 记录实例
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 泛型方法, 获取或创建实例对象(不注入对象的依赖项)
|
||||
/// </summary>
|
||||
/// <typeparam name="T">目标类型</typeparam>
|
||||
/// <param name="parameters">构造函数的参数</param>
|
||||
/// <returns></returns>
|
||||
public T GetOrCreateServiceInstance<T>(params object[] parameters)
|
||||
{
|
||||
return (T)GetOrCreateServiceInstance(typeof(T), parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空容器对象
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ISereinIoc Reset()
|
||||
{
|
||||
// 检查是否存在非托管资源
|
||||
foreach(var instancei in _dependencies.Values)
|
||||
{
|
||||
if (typeof(IDisposable).IsAssignableFrom(instancei.GetType()) && instancei is IDisposable disposable)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
}
|
||||
_typeMappings.Clear();
|
||||
_dependencies.Clear();
|
||||
_waitingForInstantiation.Clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
#region 类型的注册
|
||||
|
||||
/// <summary>
|
||||
/// 注册类型
|
||||
/// </summary>
|
||||
/// <param name="type">目标类型</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
public ISereinIoc Register(Type type, params object[] parameters)
|
||||
public ISereinIOC Register(Type type, params object[] parameters)
|
||||
{
|
||||
RegisterType(type.FullName, type);
|
||||
return this;
|
||||
@@ -114,7 +67,7 @@ namespace Serein.Library.Utils
|
||||
/// </summary>
|
||||
/// <param name="type">目标类型</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
public ISereinIoc Register<T>(params object[] parameters)
|
||||
public ISereinIOC Register<T>(params object[] parameters)
|
||||
{
|
||||
var type = typeof(T);
|
||||
RegisterType(type.FullName, type);
|
||||
@@ -122,61 +75,90 @@ namespace Serein.Library.Utils
|
||||
}
|
||||
|
||||
|
||||
public ISereinIoc Register<TService, TImplementation>(params object[] parameters)
|
||||
public ISereinIOC Register<TService, TImplementation>(params object[] parameters)
|
||||
where TImplementation : TService
|
||||
{
|
||||
var typeFullName = typeof(TService).FullName;
|
||||
RegisterType(typeFullName, typeof(TImplementation));
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 注册
|
||||
/// 尝试从容器中获取对象,如果不存在目标类型的对象,则将类型信息登记到容器,并实例化注入依赖项。
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public object GetOrInstantiate(Type type)
|
||||
{
|
||||
// 尝试从容器中获取对象
|
||||
if (!_dependencies.TryGetValue(type.FullName, out object value))
|
||||
{
|
||||
Register(type);
|
||||
|
||||
value = Instantiate(type);
|
||||
|
||||
InjectDependencies(type);
|
||||
Register(type);// 注册类型信息
|
||||
value = Instantiate(type); // 创建实例对象,并注入依赖
|
||||
_dependencies.TryAdd(type.FullName, value); // 登记到IOC容器中
|
||||
}
|
||||
|
||||
|
||||
|
||||
return value;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试从容器中获取对象,如果不存在目标类型的对象,则将类型信息登记到容器,并实例化注入依赖项。
|
||||
/// </summary>
|
||||
public T GetOrInstantiate<T>()
|
||||
{
|
||||
if(!_dependencies.TryGetValue(typeof(T).FullName, out object value))
|
||||
{
|
||||
Register(typeof(T));
|
||||
value = Instantiate(typeof(T));
|
||||
}
|
||||
|
||||
var value = Instantiate(typeof(T));
|
||||
return (T)value;
|
||||
//throw new InvalidOperationException("目标类型未创建实例");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据类型生成对应的实例,并注入其中的依赖项(类型信息不登记到IOC容器中)
|
||||
/// </summary>
|
||||
/// <param name="controllerType"></param>
|
||||
/// <param name="parameters"></param>
|
||||
/// <returns></returns>
|
||||
public object Instantiate(Type controllerType, params object[] parameters)
|
||||
{
|
||||
var instance = CreateInstance(controllerType, parameters); // 创建目标类型的实例
|
||||
if(instance != null)
|
||||
{
|
||||
InjectDependencies(instance); // 完成创建后注入实例需要的依赖项
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
#region 容器管理(清空,绑定)
|
||||
|
||||
/// <summary>
|
||||
/// 清空容器对象
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ISereinIOC Reset()
|
||||
{
|
||||
// 检查是否存在非托管资源
|
||||
foreach (var instancei in _dependencies.Values)
|
||||
{
|
||||
if (typeof(IDisposable).IsAssignableFrom(instancei.GetType()) && instancei is IDisposable disposable)
|
||||
{
|
||||
disposable?.Dispose();
|
||||
}
|
||||
}
|
||||
_unfinishedDependencies?.Clear();
|
||||
_typeMappings?.Clear();
|
||||
_dependencies?.Clear();
|
||||
_waitingForInstantiation?.Clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实例化所有已注册的类型,并尝试绑定
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ISereinIoc Build()
|
||||
public ISereinIOC Build()
|
||||
{
|
||||
// 遍历已注册类型
|
||||
foreach (var type in _typeMappings.Values.ToArray())
|
||||
{
|
||||
|
||||
if(_dependencies.ContainsKey(type.FullName))
|
||||
|
||||
if (_dependencies.ContainsKey(type.FullName))
|
||||
{
|
||||
// 已经存在实例,不用管
|
||||
}
|
||||
@@ -186,7 +168,7 @@ namespace Serein.Library.Utils
|
||||
_dependencies[type.FullName] = CreateInstance(type);
|
||||
}
|
||||
// 移除类型的注册记录
|
||||
_typeMappings.TryRemove(type.FullName,out _);
|
||||
_typeMappings.TryRemove(type.FullName, out _);
|
||||
}
|
||||
|
||||
// 注入实例的依赖项
|
||||
@@ -198,20 +180,12 @@ namespace Serein.Library.Utils
|
||||
//var instance = Instantiate(item.Value);
|
||||
|
||||
// TryInstantiateWaitingDependencies();
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public object Instantiate(Type controllerType, params object[] parameters)
|
||||
{
|
||||
var instance = CreateInstance(controllerType, parameters);
|
||||
if(instance != null)
|
||||
{
|
||||
InjectDependencies(instance);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 私有方法
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -233,14 +207,14 @@ namespace Serein.Library.Utils
|
||||
private object CreateInstance(Type type, params object[] parameters)
|
||||
{
|
||||
var instance = Activator.CreateInstance(type);
|
||||
if(_unfinishedDependencies.TryGetValue(type.FullName, out var unfinishedPropertyList))
|
||||
if (_unfinishedDependencies.TryGetValue(type.FullName, out var unfinishedPropertyList))
|
||||
{
|
||||
foreach ((object obj, PropertyInfo property) in unfinishedPropertyList)
|
||||
{
|
||||
property.SetValue(obj, instance); //注入依赖项
|
||||
}
|
||||
|
||||
if(_unfinishedDependencies.TryRemove(type.FullName, out unfinishedPropertyList))
|
||||
|
||||
if (_unfinishedDependencies.TryRemove(type.FullName, out unfinishedPropertyList))
|
||||
{
|
||||
unfinishedPropertyList.Clear();
|
||||
}
|
||||
@@ -272,19 +246,19 @@ namespace Serein.Library.Utils
|
||||
else
|
||||
{
|
||||
// 存在依赖项,但目标类型的实例暂未加载,需要等待需要实例完成注册
|
||||
var unfinishedDependenciesList = _unfinishedDependencies.GetOrAdd(propertyType.FullName, _ = new List<(object, PropertyInfo)>());
|
||||
var unfinishedDependenciesList = _unfinishedDependencies.GetOrAdd(propertyType.FullName, _ = new List<(object, PropertyInfo)>());
|
||||
var data = (instance, property);
|
||||
if (!unfinishedDependenciesList.Contains(data))
|
||||
{
|
||||
unfinishedDependenciesList.Add(data);
|
||||
}
|
||||
isPass = false;
|
||||
if (!unfinishedDependenciesList.Contains(data))
|
||||
{
|
||||
unfinishedDependenciesList.Add(data);
|
||||
}
|
||||
isPass = false;
|
||||
}
|
||||
}
|
||||
return isPass;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 再次尝试注入目标实例的依赖项
|
||||
/// </summary>
|
||||
@@ -304,10 +278,11 @@ namespace Serein.Library.Utils
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region run()
|
||||
public ISereinIoc Run<T>(Action<T> action)
|
||||
public ISereinIOC Run<T>(Action<T> action)
|
||||
{
|
||||
var service = GetOrInstantiate<T>();
|
||||
if (service != null)
|
||||
@@ -317,7 +292,7 @@ namespace Serein.Library.Utils
|
||||
return this;
|
||||
}
|
||||
|
||||
public ISereinIoc Run<T1, T2>(Action<T1, T2> action)
|
||||
public ISereinIOC Run<T1, T2>(Action<T1, T2> action)
|
||||
{
|
||||
var service1 = GetOrInstantiate<T1>();
|
||||
var service2 = GetOrInstantiate<T2>();
|
||||
@@ -326,7 +301,7 @@ namespace Serein.Library.Utils
|
||||
return this;
|
||||
}
|
||||
|
||||
public ISereinIoc Run<T1, T2, T3>(Action<T1, T2, T3> action)
|
||||
public ISereinIOC Run<T1, T2, T3>(Action<T1, T2, T3> action)
|
||||
{
|
||||
var service1 = GetOrInstantiate<T1>();
|
||||
var service2 = GetOrInstantiate<T2>();
|
||||
@@ -335,7 +310,7 @@ namespace Serein.Library.Utils
|
||||
return this;
|
||||
}
|
||||
|
||||
public ISereinIoc Run<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action)
|
||||
public ISereinIOC Run<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action)
|
||||
{
|
||||
var service1 = GetOrInstantiate<T1>();
|
||||
var service2 = GetOrInstantiate<T2>();
|
||||
@@ -345,7 +320,7 @@ namespace Serein.Library.Utils
|
||||
return this;
|
||||
}
|
||||
|
||||
public ISereinIoc Run<T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> action)
|
||||
public ISereinIOC Run<T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> action)
|
||||
{
|
||||
var service1 = GetOrInstantiate<T1>();
|
||||
var service2 = GetOrInstantiate<T2>();
|
||||
@@ -356,7 +331,7 @@ namespace Serein.Library.Utils
|
||||
return this;
|
||||
}
|
||||
|
||||
public ISereinIoc Run<T1, T2, T3, T4, T5, T6>(Action<T1, T2, T3, T4, T5, T6> action)
|
||||
public ISereinIOC Run<T1, T2, T3, T4, T5, T6>(Action<T1, T2, T3, T4, T5, T6> action)
|
||||
{
|
||||
var service1 = GetOrInstantiate<T1>();
|
||||
var service2 = GetOrInstantiate<T2>();
|
||||
@@ -368,7 +343,7 @@ namespace Serein.Library.Utils
|
||||
return this;
|
||||
}
|
||||
|
||||
public ISereinIoc Run<T1, T2, T3, T4, T5, T6, T7>(Action<T1, T2, T3, T4, T5, T6, T7> action)
|
||||
public ISereinIOC Run<T1, T2, T3, T4, T5, T6, T7>(Action<T1, T2, T3, T4, T5, T6, T7> action)
|
||||
{
|
||||
var service1 = GetOrInstantiate<T1>();
|
||||
var service2 = GetOrInstantiate<T2>();
|
||||
@@ -381,7 +356,7 @@ namespace Serein.Library.Utils
|
||||
return this;
|
||||
}
|
||||
|
||||
public ISereinIoc Run<T1, T2, T3, T4, T5, T6, T7, T8>(Action<T1, T2, T3, T4, T5, T6, T7, T8> action)
|
||||
public ISereinIOC Run<T1, T2, T3, T4, T5, T6, T7, T8>(Action<T1, T2, T3, T4, T5, T6, T7, T8> action)
|
||||
{
|
||||
var service1 = GetOrInstantiate<T1>();
|
||||
var service2 = GetOrInstantiate<T2>();
|
||||
|
||||
@@ -10,7 +10,9 @@ using System.Diagnostics;
|
||||
using System.Net.Mime;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
using static Serein.NodeFlow.FlowStarter;
|
||||
|
||||
namespace Serein.NodeFlow
|
||||
{
|
||||
@@ -47,19 +49,28 @@ namespace Serein.NodeFlow
|
||||
/// </summary>
|
||||
public event LoadDLLHandler OnDllLoad;
|
||||
/// <summary>
|
||||
/// 加载节点
|
||||
/// 加载节点事件
|
||||
/// </summary>
|
||||
public event LoadNodeHandler OnLoadNode;
|
||||
/// <summary>
|
||||
/// 连接节点
|
||||
/// 节点连接属性改变事件
|
||||
/// </summary>
|
||||
public event NodeConnectChangeHandler OnNodeConnectChange;
|
||||
/// <summary>
|
||||
/// 创建节点
|
||||
/// 节点创建时间
|
||||
/// </summary>
|
||||
public event NodeCreateHandler OnNodeCreate;
|
||||
/// <summary>
|
||||
/// 移除节点事件
|
||||
/// </summary>
|
||||
public event NodeRemoteHandler OnNodeRemote;
|
||||
/// <summary>
|
||||
/// 起始节点变化事件
|
||||
/// </summary>
|
||||
public event StartNodeChangeHandler OnStartNodeChange;
|
||||
/// <summary>
|
||||
/// 流程运行完成时间
|
||||
/// </summary>
|
||||
public event FlowRunCompleteHandler OnFlowRunComplete;
|
||||
|
||||
private FlowStarter? nodeFlowStarter = null;
|
||||
@@ -72,7 +83,7 @@ namespace Serein.NodeFlow
|
||||
/// <summary>
|
||||
/// 一种轻量的IOC容器
|
||||
/// </summary>
|
||||
public SereinIoc SereinIoc { get; } = new SereinIoc();
|
||||
// public SereinIoc SereinIoc { get; } = new SereinIoc();
|
||||
|
||||
/// <summary>
|
||||
/// 存储加载的程序集路径
|
||||
@@ -92,15 +103,17 @@ namespace Serein.NodeFlow
|
||||
|
||||
public Dictionary<string, NodeModelBase> Nodes { get; } = [];
|
||||
|
||||
public List<NodeModelBase> Regions { get; } = [];
|
||||
// public List<NodeModelBase> Regions { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 存放触发器节点(运行时全部调用)
|
||||
/// </summary>
|
||||
public List<SingleFlipflopNode> FlipflopNodes { get; } = [];
|
||||
|
||||
private NodeModelBase? _startNode = null;
|
||||
|
||||
/// <summary>
|
||||
/// 私有属性
|
||||
/// </summary>
|
||||
private NodeModelBase _startNode;
|
||||
/// <summary>
|
||||
/// 起始节点
|
||||
/// </summary>
|
||||
@@ -112,17 +125,12 @@ namespace Serein.NodeFlow
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_startNode is null)
|
||||
{
|
||||
value.IsStart = true;
|
||||
_startNode = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_startNode is not null)
|
||||
{
|
||||
_startNode.IsStart = false;
|
||||
value.IsStart = true;
|
||||
_startNode = value;
|
||||
}
|
||||
value.IsStart = true;
|
||||
_startNode = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,19 +140,32 @@ namespace Serein.NodeFlow
|
||||
/// <returns></returns>
|
||||
public async Task StartAsync()
|
||||
{
|
||||
nodeFlowStarter = new FlowStarter(SereinIoc);
|
||||
var nodes = Nodes.Values.ToList();
|
||||
var flipflopNodes = nodes.Where(it => it.MethodDetails?.MethodDynamicType == NodeType.Flipflop
|
||||
&& it.IsStart == false)
|
||||
.Select(it => it as SingleFlipflopNode)
|
||||
.ToList();
|
||||
nodeFlowStarter = new FlowStarter();
|
||||
List<SingleFlipflopNode> flipflopNodes = Nodes.Values.Where(it => it.MethodDetails?.MethodDynamicType == NodeType.Flipflop && it.IsStart == false)
|
||||
.Select(it => (SingleFlipflopNode)it)
|
||||
.Where(node => node is SingleFlipflopNode flipflopNode && flipflopNode.NotExitPreviousNode())
|
||||
.ToList();// 获取需要再运行开始之前启动的触发器节点
|
||||
var runMethodDetailess = Nodes.Values.Select(item => item.MethodDetails).ToList(); // 获取环境中所有节点的方法信息
|
||||
var initMethods = MethodDetailss.Where(it => it.MethodDynamicType == NodeType.Init).ToList();
|
||||
var loadingMethods = MethodDetailss.Where(it => it.MethodDynamicType == NodeType.Loading).ToList();
|
||||
var exitMethods = MethodDetailss.Where(it => it.MethodDynamicType == NodeType.Exit).ToList();
|
||||
await nodeFlowStarter.RunAsync(StartNode,
|
||||
this,
|
||||
runMethodDetailess,
|
||||
initMethods,
|
||||
loadingMethods,
|
||||
exitMethods,
|
||||
flipflopNodes);
|
||||
|
||||
await nodeFlowStarter.RunAsync(StartNode, this, MethodDetailss, flipflopNodes);
|
||||
if(nodeFlowStarter?.FlipFlopState == RunState.NoStart)
|
||||
{
|
||||
this.Exit(); // 未运行触发器时,才会调用结束方法
|
||||
}
|
||||
nodeFlowStarter = null;
|
||||
}
|
||||
public void Exit()
|
||||
{
|
||||
nodeFlowStarter?.Exit();
|
||||
nodeFlowStarter = null;
|
||||
OnFlowRunComplete?.Invoke(new FlowEventArgs());
|
||||
}
|
||||
|
||||
@@ -162,19 +183,6 @@ namespace Serein.NodeFlow
|
||||
|
||||
#region 对外暴露的接口
|
||||
|
||||
/// <summary>
|
||||
/// 获取方法描述
|
||||
/// </summary>
|
||||
public bool TryGetMethodDetails(string name, out MethodDetails? md)
|
||||
{
|
||||
md = MethodDetailss.FirstOrDefault(it => it.MethodName == name);
|
||||
if (md == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载项目文件
|
||||
/// </summary>
|
||||
@@ -247,27 +255,34 @@ namespace Serein.NodeFlow
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接节点
|
||||
/// 保存项目为项目文件
|
||||
/// </summary>
|
||||
/// <param name="fromNode">起始节点</param>
|
||||
/// <param name="toNode">目标节点</param>
|
||||
/// <param name="connectionType">连接关系</param>
|
||||
public void ConnectNode(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
|
||||
/// <returns></returns>
|
||||
public SereinOutputFileData SaveProject()
|
||||
{
|
||||
// 获取起始节点与目标节点
|
||||
if (!Nodes.TryGetValue(fromNodeGuid, out NodeModelBase? fromNode) || !Nodes.TryGetValue(toNodeGuid, out NodeModelBase? toNode))
|
||||
var projectData = new SereinOutputFileData()
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (fromNode is null || toNode is null)
|
||||
Librarys = LoadedAssemblies.Select(assemblies => assemblies.ToLibrary()).ToArray(),
|
||||
Nodes = Nodes.Values.Select(node => node.ToInfo()).Where(info => info is not null).ToArray(),
|
||||
StartNode = Nodes.Values.FirstOrDefault(it => it.IsStart)?.Guid,
|
||||
};
|
||||
return projectData;
|
||||
}
|
||||
/// <summary>
|
||||
/// 从文件路径中加载DLL
|
||||
/// </summary>
|
||||
/// <param name="dllPath"></param>
|
||||
/// <returns></returns>
|
||||
public void LoadDll(string dllPath)
|
||||
{
|
||||
(var assembly, var list) = LoadAssembly(dllPath);
|
||||
if (assembly is not null && list.Count > 0)
|
||||
{
|
||||
return;
|
||||
MethodDetailss.AddRange(list);
|
||||
OnDllLoad?.Invoke(new LoadDLLEventArgs(assembly, list));
|
||||
}
|
||||
// 开始连接
|
||||
ConnectNode(fromNode, toNode, connectionType); // 外部调用连接方法
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建节点
|
||||
/// </summary>
|
||||
@@ -326,66 +341,6 @@ namespace Serein.NodeFlow
|
||||
SetStartNode(nodeBase);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 从文件路径中加载DLL
|
||||
/// </summary>
|
||||
/// <param name="dllPath"></param>
|
||||
/// <returns></returns>
|
||||
public void LoadDll(string dllPath)
|
||||
{
|
||||
(var assembly, var list) = LoadAssembly(dllPath);
|
||||
if (assembly is not null && list.Count > 0)
|
||||
{
|
||||
MethodDetailss.AddRange(list);
|
||||
OnDllLoad?.Invoke(new LoadDLLEventArgs(assembly, list));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存项目为项目文件
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public SereinOutputFileData SaveProject()
|
||||
{
|
||||
var projectData = new SereinOutputFileData()
|
||||
{
|
||||
Librarys = LoadedAssemblies.Select(assemblies => assemblies.ToLibrary()).ToArray(),
|
||||
Nodes = Nodes.Values.Select(node => node.ToInfo()).Where(info => info is not null).ToArray(),
|
||||
StartNode = Nodes.Values.FirstOrDefault(it => it.IsStart)?.Guid,
|
||||
};
|
||||
return projectData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除连接关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid"></param>
|
||||
/// <param name="toNodeGuid"></param>
|
||||
/// <param name="connectionType"></param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public void RemoteConnect(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
|
||||
{
|
||||
// 获取起始节点与目标节点
|
||||
if (!Nodes.TryGetValue(fromNodeGuid, out NodeModelBase? fromNode) || !Nodes.TryGetValue(toNodeGuid, out NodeModelBase? toNode))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (fromNode is null || toNode is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fromNode.SuccessorNodes[connectionType].Remove(toNode);
|
||||
toNode.PreviousNodes[connectionType].Remove(fromNode);
|
||||
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
|
||||
toNodeGuid,
|
||||
connectionType,
|
||||
NodeConnectChangeEventArgs.ChangeTypeEnum.Remote));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除节点
|
||||
/// </summary>
|
||||
@@ -418,7 +373,7 @@ namespace Serein.NodeFlow
|
||||
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(pNode.Guid,
|
||||
remoteNode.Guid,
|
||||
pCType,
|
||||
NodeConnectChangeEventArgs.ChangeTypeEnum.Remote)); // 通知UI
|
||||
NodeConnectChangeEventArgs.ConnectChangeType.Remote)); // 通知UI
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,7 +388,7 @@ namespace Serein.NodeFlow
|
||||
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(remoteNode.Guid,
|
||||
sNode.Guid,
|
||||
sCType,
|
||||
NodeConnectChangeEventArgs.ChangeTypeEnum.Remote)); // 通知UI
|
||||
NodeConnectChangeEventArgs.ConnectChangeType.Remote)); // 通知UI
|
||||
|
||||
}
|
||||
}
|
||||
@@ -443,6 +398,68 @@ namespace Serein.NodeFlow
|
||||
OnNodeRemote?.Invoke(new NodeRemoteEventArgs(nodeGuid));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接节点
|
||||
/// </summary>
|
||||
/// <param name="fromNode">起始节点</param>
|
||||
/// <param name="toNode">目标节点</param>
|
||||
/// <param name="connectionType">连接关系</param>
|
||||
public void ConnectNode(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
|
||||
{
|
||||
// 获取起始节点与目标节点
|
||||
if (!Nodes.TryGetValue(fromNodeGuid, out NodeModelBase? fromNode) || !Nodes.TryGetValue(toNodeGuid, out NodeModelBase? toNode))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (fromNode is null || toNode is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// 开始连接
|
||||
ConnectNode(fromNode, toNode, connectionType); // 外部调用连接方法
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除连接关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid"></param>
|
||||
/// <param name="toNodeGuid"></param>
|
||||
/// <param name="connectionType"></param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public void RemoteConnect(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
|
||||
{
|
||||
// 获取起始节点与目标节点
|
||||
if (!Nodes.TryGetValue(fromNodeGuid, out NodeModelBase? fromNode) || !Nodes.TryGetValue(toNodeGuid, out NodeModelBase? toNode))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (fromNode is null || toNode is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fromNode.SuccessorNodes[connectionType].Remove(toNode);
|
||||
toNode.PreviousNodes[connectionType].Remove(fromNode);
|
||||
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
|
||||
toNodeGuid,
|
||||
connectionType,
|
||||
NodeConnectChangeEventArgs.ConnectChangeType.Remote));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取方法描述
|
||||
/// </summary>
|
||||
public bool TryGetMethodDetails(string name, out MethodDetails? md)
|
||||
{
|
||||
md = MethodDetailss.FirstOrDefault(it => it.MethodName == name);
|
||||
if (md == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置起点控件
|
||||
/// </summary>
|
||||
@@ -494,14 +511,14 @@ namespace Serein.NodeFlow
|
||||
{
|
||||
// 加载DLL,创建 MethodDetails、实例作用对象、委托方法
|
||||
var itemMethodDetails = MethodDetailsHelperTmp.GetList(item, false);
|
||||
foreach (var md in itemMethodDetails)
|
||||
{
|
||||
// var instanceType =
|
||||
// Activator.CreateInstance(md.ActingInstanceType);
|
||||
// SereinIoc.RegisterInstantiate(md.ActingInstance);
|
||||
SereinIoc.Register(md.ActingInstanceType);
|
||||
}
|
||||
methodDetails.AddRange(itemMethodDetails);
|
||||
//foreach (var md in itemMethodDetails)
|
||||
//{
|
||||
// // var instanceType =
|
||||
// // Activator.CreateInstance(md.ActingInstanceType);
|
||||
// // SereinIoc.RegisterInstantiate(md.ActingInstance);
|
||||
// SereinIoc.Register(md.ActingInstanceType);
|
||||
//}
|
||||
}
|
||||
LoadedAssemblies.Add(assembly); // 将加载的程序集添加到列表中
|
||||
LoadedAssemblyPaths.Add(dllPath); // 记录加载的DLL路径
|
||||
@@ -514,7 +531,6 @@ namespace Serein.NodeFlow
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 连接节点
|
||||
/// </summary>
|
||||
@@ -573,7 +589,7 @@ namespace Serein.NodeFlow
|
||||
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
|
||||
toNode.Guid,
|
||||
connectionType,
|
||||
NodeConnectChangeEventArgs.ChangeTypeEnum.Create)); // 通知UI
|
||||
NodeConnectChangeEventArgs.ConnectChangeType.Create)); // 通知UI
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -589,20 +605,11 @@ namespace Serein.NodeFlow
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 视觉元素交互
|
||||
|
||||
#region 本地交互(WPF)
|
||||
#region 网络交互
|
||||
|
||||
#endregion
|
||||
|
||||
#region 网络交互(通过Socket的方式进行操作)
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
public static class FlowFunc
|
||||
{
|
||||
public static Library.Entity.Library ToLibrary(this Assembly assembly)
|
||||
@@ -625,6 +632,22 @@ namespace Serein.NodeFlow
|
||||
_ => throw new NotImplementedException("未定义的流程状态")
|
||||
};
|
||||
}
|
||||
|
||||
public static bool NotExitPreviousNode(this SingleFlipflopNode node)
|
||||
{
|
||||
ConnectionType[] ct = [ConnectionType.IsSucceed,
|
||||
ConnectionType.IsFail,
|
||||
ConnectionType.IsError,
|
||||
ConnectionType.Upstream];
|
||||
foreach (ConnectionType ctType in ct)
|
||||
{
|
||||
if(node.PreviousNodes[ctType].Count > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,69 +16,135 @@ namespace Serein.NodeFlow
|
||||
/// <param name="methodDetails"></param>
|
||||
public class FlowStarter
|
||||
{
|
||||
public FlowStarter(ISereinIoc serviceContainer/*, List<MethodDetails> methodDetails*/)
|
||||
public FlowStarter()
|
||||
{
|
||||
SereinIoc = serviceContainer;
|
||||
|
||||
SereinIOC = new SereinIOC();
|
||||
}
|
||||
/// <summary>
|
||||
/// 流程运行状态
|
||||
/// </summary>
|
||||
public enum RunState
|
||||
{
|
||||
/// <summary>
|
||||
/// 等待开始
|
||||
/// </summary>
|
||||
NoStart,
|
||||
/// <summary>
|
||||
/// 正在运行
|
||||
/// </summary>
|
||||
Running,
|
||||
/// <summary>
|
||||
/// 运行完成
|
||||
/// </summary>
|
||||
Completion,
|
||||
}
|
||||
/// <summary>
|
||||
/// 控制触发器的结束
|
||||
/// </summary>
|
||||
private NodeRunCts FlipFlopCts { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// 运行状态
|
||||
/// </summary>
|
||||
public RunState FlowState { get; private set; } = RunState.NoStart;
|
||||
public RunState FlipFlopState { get; private set; } = RunState.NoStart;
|
||||
|
||||
/// <summary>
|
||||
/// 运行时的IOC容器
|
||||
/// </summary>
|
||||
private ISereinIOC SereinIOC { get; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// 结束运行时需要执行的方法
|
||||
/// </summary>
|
||||
private Action ExitAction { get; set; } = null;
|
||||
/// <summary>
|
||||
/// 运行的上下文
|
||||
/// </summary>
|
||||
private IDynamicContext Context { get; set; } = null;
|
||||
|
||||
|
||||
private ISereinIoc SereinIoc { get; }
|
||||
// private List<MethodDetails> MethodDetailss { get; }
|
||||
private Action ExitAction { get; set; } = null; //退出方法
|
||||
private IDynamicContext Context { get; set; } = null; //上下文
|
||||
public NodeRunCts MainCts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 开始运行
|
||||
/// </summary>
|
||||
/// <param name="nodes"></param>
|
||||
/// <param name="startNode">起始节点</param>
|
||||
/// <param name="env">运行环境</param>
|
||||
/// <param name="runMd">环境中已加载的所有节点方法</param>
|
||||
/// <param name="flipflopNodes">触发器节点</param>
|
||||
/// <returns></returns>
|
||||
// public async Task RunAsync(List<NodeModelBase> nodes, IFlowEnvironment flowEnvironment)
|
||||
public async Task RunAsync(NodeModelBase startNode, IFlowEnvironment flowEnvironment, List<MethodDetails> methodDetailss, List<SingleFlipflopNode> flipflopNodes)
|
||||
public async Task RunAsync(NodeModelBase startNode,
|
||||
IFlowEnvironment env,
|
||||
List<MethodDetails> runMd,
|
||||
List<MethodDetails> initMethods,
|
||||
List<MethodDetails> loadingMethods,
|
||||
List<MethodDetails> exitMethods,
|
||||
List<SingleFlipflopNode> flipflopNodes)
|
||||
{
|
||||
// var startNode = nodes.FirstOrDefault(p => p.IsStart);
|
||||
if (startNode == null) { return; }
|
||||
|
||||
FlowState = RunState.Running; // 开始运行
|
||||
|
||||
if (startNode == null) {
|
||||
FlowState = RunState.Completion; // 不存在起点,退出流程
|
||||
return;
|
||||
}
|
||||
|
||||
// 判断使用哪一种流程上下文
|
||||
var isNetFramework = true;
|
||||
|
||||
if (isNetFramework)
|
||||
{
|
||||
Context = new Serein.Library.Framework.NodeFlow.DynamicContext(SereinIoc, flowEnvironment);
|
||||
Context = new Serein.Library.Framework.NodeFlow.DynamicContext(SereinIOC, env);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context = new Serein.Library.Core.NodeFlow.DynamicContext(SereinIoc, flowEnvironment);
|
||||
Context = new Serein.Library.Core.NodeFlow.DynamicContext(SereinIOC, env);
|
||||
}
|
||||
|
||||
MainCts = SereinIoc.GetOrCreateServiceInstance<NodeRunCts>();
|
||||
|
||||
foreach (var md in methodDetailss)
|
||||
#region 初始化运行环境的Ioc容器
|
||||
// 清除节点使用的对象
|
||||
foreach (var nodeMd in runMd)
|
||||
{
|
||||
SereinIoc.Register(md.ActingInstanceType);
|
||||
nodeMd.ActingInstance = null;
|
||||
}
|
||||
SereinIoc.Build();
|
||||
foreach (var md in flipflopNodes.Select(it => it.MethodDetails).ToArray())
|
||||
SereinIOC.Reset(); // 开始运行时清空ioc中注册的实例
|
||||
// 初始化ioc容器中的类型对象
|
||||
foreach (var md in runMd)
|
||||
{
|
||||
md.ActingInstance = SereinIoc.GetOrCreateServiceInstance(md.ActingInstanceType);
|
||||
SereinIOC.Register(md.ActingInstanceType);
|
||||
}
|
||||
foreach (var md in methodDetailss)
|
||||
SereinIOC.Build();
|
||||
foreach (var md in runMd)
|
||||
{
|
||||
md.ActingInstance = SereinIoc.GetOrCreateServiceInstance(md.ActingInstanceType);
|
||||
md.ActingInstance = SereinIOC.GetOrInstantiate(md.ActingInstanceType);
|
||||
}
|
||||
|
||||
var initMethods = methodDetailss.Where(it => it.MethodDynamicType == NodeType.Init).ToList();
|
||||
var loadingMethods = methodDetailss.Where(it => it.MethodDynamicType == NodeType.Loading).ToList();
|
||||
var exitMethods = methodDetailss.Where(it => it.MethodDynamicType == NodeType.Exit).ToList();
|
||||
//foreach (var md in flipflopNodes.Select(it => it.MethodDetails).ToArray())
|
||||
//{
|
||||
// md.ActingInstance = SereinIoc.GetOrCreateServiceInstance(md.ActingInstanceType);
|
||||
//}
|
||||
#endregion
|
||||
|
||||
|
||||
#region 创建Node中初始化、加载时、退出时调用的方法
|
||||
|
||||
foreach (var md in initMethods) // 初始化
|
||||
{
|
||||
md.ActingInstance ??= Context.SereinIoc.GetOrInstantiate(md.ActingInstanceType);
|
||||
}
|
||||
foreach (var md in loadingMethods) // 加载
|
||||
{
|
||||
md.ActingInstance ??= Context.SereinIoc.GetOrInstantiate(md.ActingInstanceType);
|
||||
}
|
||||
foreach (var md in exitMethods) // 初始化
|
||||
{
|
||||
md.ActingInstance ??= Context.SereinIoc.GetOrInstantiate(md.ActingInstanceType);
|
||||
}
|
||||
|
||||
object?[]? args = [Context];
|
||||
ExitAction = () =>
|
||||
{
|
||||
//ServiceContainer.Run<WebServer>((web) =>
|
||||
//{
|
||||
// web?.Stop();
|
||||
//});
|
||||
foreach (MethodDetails? md in exitMethods)
|
||||
{
|
||||
md.ActingInstance = Context.SereinIoc.GetOrInstantiate(md.ActingInstanceType);
|
||||
object?[]? args = [Context];
|
||||
object?[]? data = [md.ActingInstance, args];
|
||||
md.MethodDelegate.DynamicInvoke(data);
|
||||
}
|
||||
@@ -86,53 +152,62 @@ namespace Serein.NodeFlow
|
||||
{
|
||||
Context.NodeRunCts.Cancel();
|
||||
}
|
||||
if (MainCts != null && !MainCts.IsCancellationRequested) MainCts.Cancel();
|
||||
SereinIoc.Reset();
|
||||
if (FlipFlopCts != null && !FlipFlopCts.IsCancellationRequested)
|
||||
{
|
||||
FlipFlopCts.Cancel();
|
||||
}
|
||||
FlowState = RunState.Completion;
|
||||
FlipFlopState = RunState.Completion;
|
||||
};
|
||||
Context.SereinIoc.Build();
|
||||
#endregion
|
||||
|
||||
#region 执行初始化,然后绑定IOC容器,再执行加载时
|
||||
|
||||
foreach (var md in initMethods) // 初始化 - 调用方法
|
||||
{
|
||||
md.ActingInstance ??= Context.SereinIoc.GetOrInstantiate(md.ActingInstanceType);
|
||||
object?[]? args = [Context];
|
||||
object?[]? data = [md.ActingInstance, args];
|
||||
md.MethodDelegate.DynamicInvoke(data);
|
||||
}
|
||||
Context.SereinIoc.Build();
|
||||
foreach (var md in loadingMethods) // 加载
|
||||
{
|
||||
md.ActingInstance ??= Context.SereinIoc.GetOrInstantiate(md.ActingInstanceType);
|
||||
object?[]? args = [Context];
|
||||
object?[]? data = [md.ActingInstance, args];
|
||||
md.MethodDelegate.DynamicInvoke(data);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
// 运行触发器节点
|
||||
var singleFlipflopNodes = flipflopNodes.Select(it => (SingleFlipflopNode)it).ToArray();
|
||||
|
||||
// 使用 TaskCompletionSource 创建未启动的任务
|
||||
var tasks = singleFlipflopNodes.Select(async node =>
|
||||
{
|
||||
await FlipflopExecute(node, flowEnvironment);
|
||||
}).ToArray();
|
||||
_ = Task.WhenAll(tasks);
|
||||
|
||||
// 节点任务的启动
|
||||
try
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
|
||||
if (flipflopNodes.Count > 0)
|
||||
{
|
||||
await startNode.StartExecution(Context);
|
||||
//await Task.WhenAll([startNode.StartExecution(Context), .. tasks]);
|
||||
});
|
||||
FlipFlopState = RunState.Running;
|
||||
// 如果存在需要启动的触发器,则开始启动
|
||||
FlipFlopCts = SereinIOC.GetOrInstantiate<NodeRunCts>();
|
||||
// 使用 TaskCompletionSource 创建未启动的触发器任务
|
||||
var tasks = flipflopNodes.Select(async node =>
|
||||
{
|
||||
await FlipflopExecute(node, env);
|
||||
}).ToArray();
|
||||
_ = Task.WhenAll(tasks);
|
||||
}
|
||||
await startNode.StartExecution(Context);
|
||||
// 等待结束
|
||||
while (!MainCts.IsCancellationRequested)
|
||||
if(FlipFlopCts != null)
|
||||
{
|
||||
await Task.Delay(100);
|
||||
while (!FlipFlopCts.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Console.Out.WriteLineAsync(ex.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -140,17 +215,15 @@ namespace Serein.NodeFlow
|
||||
/// </summary>
|
||||
private async Task FlipflopExecute(SingleFlipflopNode singleFlipFlopNode, IFlowEnvironment flowEnvironment)
|
||||
{
|
||||
DynamicContext context = new DynamicContext(SereinIoc, flowEnvironment);
|
||||
DynamicContext context = new DynamicContext(SereinIOC, flowEnvironment);
|
||||
MethodDetails md = singleFlipFlopNode.MethodDetails;
|
||||
var del = md.MethodDelegate;
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
//var func = md.ExplicitDatas.Length == 0 ? (Func<object, object, Task<FlipflopContext<dynamic>>>)del : (Func<object, object[], Task<FlipflopContext<dynamic>>>)del;
|
||||
var func = md.ExplicitDatas.Length == 0 ? (Func<object, object, Task<IFlipflopContext>>)del : (Func<object, object[], Task<IFlipflopContext>>)del;
|
||||
|
||||
while (!MainCts.IsCancellationRequested) // 循环中直到栈为空才会退出
|
||||
while (!FlipFlopCts.IsCancellationRequested) // 循环中直到栈为空才会退出
|
||||
{
|
||||
object?[]? parameters = singleFlipFlopNode.GetParameters(context, md);
|
||||
// 调用委托并获取结果
|
||||
@@ -168,7 +241,7 @@ namespace Serein.NodeFlow
|
||||
|
||||
var tasks = singleFlipFlopNode.SuccessorNodes[connection].Select(nextNode =>
|
||||
{
|
||||
var context = new DynamicContext(SereinIoc,flowEnvironment);
|
||||
var context = new DynamicContext(SereinIOC,flowEnvironment);
|
||||
nextNode.PreviousNode = singleFlipFlopNode;
|
||||
return nextNode.StartExecution(context);
|
||||
}).ToArray();
|
||||
|
||||
@@ -7,16 +7,6 @@ using System.Reflection;
|
||||
|
||||
namespace Serein.NodeFlow.Tool;
|
||||
|
||||
|
||||
//public static class DelegateCache
|
||||
//{
|
||||
// /// <summary>
|
||||
// /// 委托缓存全局字典
|
||||
// /// </summary>
|
||||
// //public static ConcurrentDictionary<string, Delegate> GlobalDicDelegates { get; } = new ConcurrentDictionary<string, Delegate>();
|
||||
//}
|
||||
|
||||
|
||||
public static class MethodDetailsHelperTmp
|
||||
{
|
||||
/// <summary>
|
||||
@@ -211,190 +201,3 @@ public static class MethodDetailsHelperTmp
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class MethodDetailsHelper
|
||||
{
|
||||
// 缓存的实例对象(键:类型名称)
|
||||
// public static ConcurrentDictionary<string, object> DynamicInstanceToType { get; } = new ConcurrentDictionary<string, object>();
|
||||
// 缓存的实例对象 (键:生成的方法名称)
|
||||
// public static ConcurrentDictionary<string, object> DynamicInstance { get; } = new ConcurrentDictionary<string, object>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 生成方法信息
|
||||
/// </summary>
|
||||
/// <param name="serviceContainer"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static ConcurrentDictionary<string, MethodDetails> GetDict(ISereinIoc serviceContainer, Type type, bool isNetFramework)
|
||||
{
|
||||
var methodDetailsDictionary = new ConcurrentDictionary<string, MethodDetails>();
|
||||
var assemblyName = type.Assembly.GetName().Name;
|
||||
var methods = GetMethodsToProcess(type, isNetFramework);
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
|
||||
var methodDetails = CreateMethodDetails(serviceContainer, type, method, assemblyName, isNetFramework);
|
||||
|
||||
methodDetailsDictionary.TryAdd(methodDetails.MethodName, methodDetails);
|
||||
}
|
||||
|
||||
return methodDetailsDictionary;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取处理方法
|
||||
/// </summary>
|
||||
private static IEnumerable<MethodInfo> GetMethodsToProcess(Type type, bool isNetFramework)
|
||||
{
|
||||
if (isNetFramework)
|
||||
{
|
||||
|
||||
return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(m => m.GetCustomAttribute<NodeActionAttribute>()?.Scan == true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(m => m.GetCustomAttribute<NodeActionAttribute>()?.Scan == true);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 创建方法信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static MethodDetails CreateMethodDetails(ISereinIoc serviceContainer, Type type, MethodInfo method, string assemblyName, bool isNetFramework)
|
||||
{
|
||||
|
||||
var methodName = method.Name;
|
||||
var attribute = method.GetCustomAttribute<NodeActionAttribute>();
|
||||
var explicitDataOfParameters = GetExplicitDataOfParameters(method.GetParameters());
|
||||
// 生成委托
|
||||
var methodDelegate = GenerateMethodDelegate(type, // 方法所在的对象类型
|
||||
method, // 方法信息
|
||||
method.GetParameters(),// 方法参数
|
||||
method.ReturnType);// 返回值
|
||||
|
||||
|
||||
var dllTypeName = $"{assemblyName}.{type.Name}";
|
||||
serviceContainer.Register(type);
|
||||
object instance = serviceContainer.GetOrCreateServiceInstance(type);
|
||||
var dllTypeMethodName = $"{assemblyName}.{type.Name}.{method.Name}";
|
||||
|
||||
return new MethodDetails
|
||||
{
|
||||
ActingInstanceType = type,
|
||||
ActingInstance = instance,
|
||||
MethodName = dllTypeMethodName,
|
||||
MethodDelegate = methodDelegate,
|
||||
MethodDynamicType = attribute.MethodDynamicType,
|
||||
MethodLockName = attribute.LockName,
|
||||
MethodTips = attribute.MethodTips,
|
||||
ExplicitDatas = explicitDataOfParameters,
|
||||
ReturnType = method.ReturnType,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private static ExplicitData[] GetExplicitDataOfParameters(ParameterInfo[] parameters)
|
||||
{
|
||||
|
||||
return parameters.Select((it, index) =>
|
||||
{
|
||||
//Console.WriteLine($"{it.Name}-{it.HasDefaultValue}-{it.DefaultValue}");
|
||||
string explicitTypeName = GetExplicitTypeName(it.ParameterType);
|
||||
var items = GetExplicitItems(it.ParameterType, explicitTypeName);
|
||||
if ("Bool".Equals(explicitTypeName)) explicitTypeName = "Select"; // 布尔值 转为 可选类型
|
||||
|
||||
|
||||
|
||||
return new ExplicitData
|
||||
{
|
||||
IsExplicitData = it.HasDefaultValue,
|
||||
Index = index,
|
||||
ExplicitType = it.ParameterType,
|
||||
ExplicitTypeName = explicitTypeName,
|
||||
DataType = it.ParameterType,
|
||||
ParameterName = it.Name,
|
||||
DataValue = it.HasDefaultValue ? it.DefaultValue.ToString() : "",
|
||||
Items = items.ToArray(),
|
||||
};
|
||||
|
||||
|
||||
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
private static string GetExplicitTypeName(Type type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
Type t when t.IsEnum => "Select",
|
||||
Type t when t == typeof(bool) => "Bool",
|
||||
Type t when t == typeof(string) => "Value",
|
||||
Type t when t == typeof(int) => "Value",
|
||||
Type t when t == typeof(double) => "Value",
|
||||
_ => "Value"
|
||||
};
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetExplicitItems(Type type, string explicitTypeName)
|
||||
{
|
||||
return explicitTypeName switch
|
||||
{
|
||||
"Select" => Enum.GetNames(type),
|
||||
"Bool" => ["True", "False"],
|
||||
_ => []
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private static Delegate GenerateMethodDelegate(Type type, MethodInfo methodInfo, ParameterInfo[] parameters, Type returnType)
|
||||
{
|
||||
var parameterTypes = parameters.Select(p => p.ParameterType).ToArray();
|
||||
var parameterCount = parameters.Length;
|
||||
|
||||
if (returnType == typeof(void))
|
||||
{
|
||||
if (parameterCount == 0)
|
||||
{
|
||||
// 无返回值,无参数
|
||||
return ExpressionHelper.MethodCaller(type, methodInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 无返回值,有参数
|
||||
return ExpressionHelper.MethodCaller(type, methodInfo, parameterTypes);
|
||||
}
|
||||
}
|
||||
// else if (returnType == typeof(Task<FlipflopContext)) // 触发器
|
||||
else if (FlipflopFunc.IsTaskOfFlipflop(returnType)) // 触发器
|
||||
{
|
||||
if (parameterCount == 0)
|
||||
{
|
||||
// 有返回值,无参数
|
||||
return ExpressionHelper.MethodCallerAsync(type, methodInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 有返回值,有参数
|
||||
return ExpressionHelper.MethodCallerAsync(type, methodInfo, parameterTypes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (parameterCount == 0)
|
||||
{
|
||||
// 有返回值,无参数
|
||||
return ExpressionHelper.MethodCallerHaveResult(type, methodInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 有返回值,有参数
|
||||
return ExpressionHelper.MethodCallerHaveResult(type, methodInfo, parameterTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,65 +45,45 @@ namespace Serein.WorkBench
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
/// <summary>
|
||||
/// 一种轻量的IOC容器
|
||||
/// </summary>
|
||||
private SereinIoc ServiceContainer { get; } = new SereinIoc();
|
||||
|
||||
/// <summary>
|
||||
/// 全局捕获Console输出事件,打印在这个窗体里面
|
||||
/// </summary>
|
||||
private readonly LogWindow logWindow;
|
||||
|
||||
/// <summary>
|
||||
/// 存储加载的程序集
|
||||
/// </summary>
|
||||
// private readonly List<Assembly> loadedAssemblies = [];
|
||||
/// <summary>
|
||||
/// 存储加载的程序集路径
|
||||
/// </summary>
|
||||
// private readonly List<string> loadedAssemblyPaths = [];
|
||||
|
||||
/// <summary>
|
||||
/// 存储所有方法信息
|
||||
/// </summary>
|
||||
// private static ConcurrentDictionary<string, MethodDetails> DllMethodDetails { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 存储所有与节点有关的控件
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, NodeControlBase> NodeControls = [];
|
||||
/// <summary>
|
||||
/// 存储所有的连接
|
||||
/// </summary>
|
||||
private readonly List<Connection> Connections = [];
|
||||
|
||||
/// <summary>
|
||||
/// 存放触发器节点(运行时全部调用)
|
||||
/// </summary>
|
||||
// private readonly List<SingleFlipflopNode> flipflopNodes = [];
|
||||
|
||||
/// <summary>
|
||||
/// 节点的命名空间
|
||||
/// </summary>
|
||||
public const string NodeSpaceName = $"{nameof(Serein)}.{nameof(Serein.NodeFlow)}.{nameof(Serein.NodeFlow.Model)}";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 流程运行环境
|
||||
/// </summary>
|
||||
private IFlowEnvironment FlowEnvironment;
|
||||
private IFlowEnvironment FlowEnvironment { get; }
|
||||
private MainWindowViewModel ViewModel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 流程启动器
|
||||
/// 存储所有与节点有关的控件
|
||||
/// </summary>
|
||||
// private FlowStarter nodeFlowStarter;
|
||||
private Dictionary<string, NodeControlBase> NodeControls { get; } = [];
|
||||
/// <summary>
|
||||
/// 存储所有的连接
|
||||
/// </summary>
|
||||
private List<Connection> Connections { get; } = [];
|
||||
|
||||
|
||||
|
||||
#region 与画布相关的字段
|
||||
|
||||
/// <summary>
|
||||
/// 当前选取的控件
|
||||
/// </summary>
|
||||
private readonly List<NodeControlBase> selectControls = [];
|
||||
|
||||
/// <summary>
|
||||
/// 拖动创建节点控件时的鼠标位置
|
||||
/// </summary>
|
||||
private Point canvasDropPosition;
|
||||
|
||||
/// <summary>
|
||||
/// 记录拖动开始时的鼠标位置
|
||||
/// </summary>
|
||||
@@ -154,20 +134,14 @@ namespace Serein.WorkBench
|
||||
private TranslateTransform translateTransform;
|
||||
#endregion
|
||||
|
||||
private Point canvasDropPosition;
|
||||
|
||||
|
||||
// private MainWindowViewModel mainWindowViewModel { get; }
|
||||
public MainWindow()
|
||||
{
|
||||
// mainWindowViewModel = new MainWindowViewModel(this);
|
||||
InitializeComponent();
|
||||
ViewModel = new MainWindowViewModel(this);
|
||||
FlowEnvironment = ViewModel.FlowEnvironment;
|
||||
|
||||
|
||||
|
||||
InitializeComponent();
|
||||
logWindow = new LogWindow();
|
||||
logWindow.Show();
|
||||
|
||||
// 重定向 Console 输出
|
||||
var logTextWriter = new LogTextWriter(WriteLog);
|
||||
Console.SetOut(logTextWriter);
|
||||
@@ -177,7 +151,6 @@ namespace Serein.WorkBench
|
||||
|
||||
private void InitFlowEvent()
|
||||
{
|
||||
FlowEnvironment = new FlowEnvironment();
|
||||
FlowEnvironment.OnDllLoad += FlowEnvironment_DllLoadEvent;
|
||||
FlowEnvironment.OnLoadNode += FlowEnvironment_NodeLoadEvent;
|
||||
FlowEnvironment.OnStartNodeChange += FlowEnvironment_StartNodeChangeEvent;
|
||||
@@ -188,8 +161,6 @@ namespace Serein.WorkBench
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void InitUI()
|
||||
{
|
||||
canvasTransformGroup = new TransformGroup();
|
||||
@@ -226,7 +197,6 @@ namespace Serein.WorkBench
|
||||
WriteLog("-------运行完成---------\r\n");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 加载了DLL文件,dll内容
|
||||
/// </summary>
|
||||
@@ -287,23 +257,8 @@ namespace Serein.WorkBench
|
||||
|
||||
NodeControls.TryAdd(nodeInfo.Guid, nodeControl); // 存放对应的控件
|
||||
PlaceNodeOnCanvas(nodeControl, nodeInfo.Position.X, nodeInfo.Position.Y); // 配置节点,并放置在画布上
|
||||
|
||||
|
||||
// 添加到画布
|
||||
//FlowChartCanvas.Dispatcher.Invoke(() =>
|
||||
//{
|
||||
// // 添加控件到画布
|
||||
// FlowChartCanvas.Children.Add(nodeControl);
|
||||
// Canvas.SetLeft(nodeControl, nodeInfo.Position.x);
|
||||
// Canvas.SetTop(nodeControl, nodeInfo.Position.y);
|
||||
// nodeControls.TryAdd(nodeInfo.Guid, nodeControl); // 存放对应的控件
|
||||
// ConfigureContextMenu(nodeControl); // 配置节点右键菜单
|
||||
// ConfigureNodeEvents(nodeControl); // 配置节点事件
|
||||
//});
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 节点连接关系变更
|
||||
/// </summary>
|
||||
@@ -319,7 +274,7 @@ namespace Serein.WorkBench
|
||||
return;
|
||||
}
|
||||
ConnectionType connectionType = eventArgs.ConnectionType;
|
||||
if(eventArgs.ChangeType == NodeConnectChangeEventArgs.ChangeTypeEnum.Create)
|
||||
if(eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Create)
|
||||
{
|
||||
// 添加连接
|
||||
var connection = new Connection
|
||||
@@ -334,7 +289,7 @@ namespace Serein.WorkBench
|
||||
Connections.Add(connection);
|
||||
EndConnection();
|
||||
}
|
||||
else if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ChangeTypeEnum.Remote)
|
||||
else if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Remote)
|
||||
{
|
||||
// 需要移除连接
|
||||
var removeConnections = Connections.Where(c => c.Start.ViewModel.Node.Guid.Equals(fromNodeGuid)
|
||||
@@ -1403,7 +1358,7 @@ namespace Serein.WorkBench
|
||||
/// <param name="e"></param>
|
||||
private void ButtonDebugFlipflopNode_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
FlowEnvironment.Exit();
|
||||
FlowEnvironment.Exit(); // 在运行平台上点击了退出
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Serein.Library.Attributes;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Attributes;
|
||||
using Serein.Library.Entity;
|
||||
using Serein.Library.Utils;
|
||||
using Serein.NodeFlow;
|
||||
@@ -18,64 +19,13 @@ namespace Serein.WorkBench
|
||||
public class MainWindowViewModel
|
||||
{
|
||||
private readonly MainWindow window ;
|
||||
public IFlowEnvironment FlowEnvironment { get; set; }
|
||||
public MainWindowViewModel(MainWindow window)
|
||||
{
|
||||
FlowEnvironment = new FlowEnvironment();
|
||||
this.window = window;
|
||||
}
|
||||
|
||||
public FlowEnvironment FlowEnvironment { get; set; }
|
||||
|
||||
|
||||
#region 加载项目文件
|
||||
public void LoadProjectFile(SereinOutputFileData projectFile)
|
||||
{
|
||||
var dllPaths = projectFile.Librarys.Select(it => it.Path).ToList();
|
||||
foreach (var dll in dllPaths)
|
||||
{
|
||||
var filePath = System.IO.Path.GetFullPath(System.IO.Path.Combine(App.FileDataPath, dll));
|
||||
//LoadAssembly(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private void DisplayControlDll(Assembly assembly,
|
||||
List<MethodDetails> conditionTypes,
|
||||
List<MethodDetails> actionTypes,
|
||||
List<MethodDetails> flipflopMethods)
|
||||
{
|
||||
|
||||
var dllControl = new DllControl
|
||||
{
|
||||
Header = "DLL name : " + assembly.GetName().Name // 设置控件标题为程序集名称
|
||||
};
|
||||
|
||||
|
||||
foreach (var item in actionTypes)
|
||||
{
|
||||
dllControl.AddAction(item.Clone()); // 添加动作类型到控件
|
||||
}
|
||||
foreach (var item in flipflopMethods)
|
||||
{
|
||||
dllControl.AddFlipflop(item.Clone()); // 添加触发器方法到控件
|
||||
}
|
||||
|
||||
/*foreach (var item in stateTypes)
|
||||
{
|
||||
dllControl.AddState(item);
|
||||
}*/
|
||||
|
||||
window.DllStackPanel.Children.Add(dllControl); // 将控件添加到界面上显示
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,270 +0,0 @@
|
||||
namespace DySerin;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*public class ConditionNode : NodeBase, ICondition
|
||||
{
|
||||
private Func<bool> ConditionFunc { get; set; }
|
||||
|
||||
public ConditionNode(Func<bool> conditionFunc)
|
||||
{
|
||||
ConditionFunc = conditionFunc;
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
if (ConditionFunc())
|
||||
{
|
||||
EnterTrueBranch();
|
||||
}
|
||||
else
|
||||
{
|
||||
EnterFalseBranch();
|
||||
}
|
||||
}
|
||||
|
||||
// 实现条件接口的方法
|
||||
public bool Evaluate(DynamicContext context)
|
||||
{
|
||||
Context = context; // 更新节点的上下文
|
||||
return ConditionFunc();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class ActionNode : NodeBase, IAction
|
||||
{
|
||||
private Action ActionMethod { get; set; }
|
||||
|
||||
public ActionNode(Action actionMethod)
|
||||
{
|
||||
ActionMethod = actionMethod;
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
ActionMethod();
|
||||
EnterTrueBranch(); // 动作成功,进入真分支
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 可添加异常处理逻辑
|
||||
Return(); // 动作失败,终止节点
|
||||
}
|
||||
}
|
||||
|
||||
// 实现动作接口的方法
|
||||
public void Execute(DynamicContext context)
|
||||
{
|
||||
Context = context; // 更新节点的上下文
|
||||
Execute();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// 根节点
|
||||
/// </summary>
|
||||
public abstract class NodeControl : UserControl
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
public abstract void Execute(NodeContext context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 条件节点
|
||||
/// </summary>
|
||||
public class ConditionNodeControl : NodeControl
|
||||
{
|
||||
public Func<NodeContext, bool> Condition { get; set; }
|
||||
public NodeControl TrueNode { get; set; }
|
||||
public NodeControl FalseNode { get; set; }
|
||||
|
||||
public ConditionNodeControl()
|
||||
{
|
||||
this.Content = new TextBlock { Text = "条件节点" };
|
||||
this.Background = Brushes.LightBlue;
|
||||
}
|
||||
|
||||
public override void Execute(NodeContext context)
|
||||
{
|
||||
if (Condition(context))
|
||||
{
|
||||
TrueNode?.Execute(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
FalseNode?.Execute(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 动作节点
|
||||
/// </summary>
|
||||
public class ActionNodeControl : NodeControl
|
||||
{
|
||||
public Action<NodeContext> Action { get; set; }
|
||||
|
||||
public ActionNodeControl()
|
||||
{
|
||||
this.Content = new TextBlock { Text = "动作节点" };
|
||||
this.Background = Brushes.LightGreen;
|
||||
}
|
||||
|
||||
public override void Execute(NodeContext context)
|
||||
{
|
||||
Action?.Invoke(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 状态节点
|
||||
/// </summary>
|
||||
public class StateNodeControl : NodeControl
|
||||
{
|
||||
public Func<NodeContext, object> StateFunction { get; set; }
|
||||
|
||||
public StateNodeControl()
|
||||
{
|
||||
this.Content = new TextBlock { Text = "状态节点" };
|
||||
this.Background = Brushes.LightYellow;
|
||||
}
|
||||
|
||||
public override void Execute(NodeContext context)
|
||||
{
|
||||
var result = StateFunction(context);
|
||||
context.Set("StateResult", result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 节点上下文
|
||||
/// </summary>
|
||||
public class NodeContext
|
||||
{
|
||||
private readonly Dictionary<string, object> _data = new Dictionary<string, object>();
|
||||
|
||||
public void Set<T>(string key, T value)
|
||||
{
|
||||
_data[key] = value;
|
||||
}
|
||||
|
||||
public T Get<T>(string key)
|
||||
{
|
||||
return _data.ContainsKey(key) ? (T)_data[key] : default;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
public class Context
|
||||
{
|
||||
public Dictionary<string, object> Data { get; set; } = new Dictionary<string, object>();
|
||||
public void Set<T>(string key, T value)
|
||||
{
|
||||
Data[key] = value;
|
||||
}
|
||||
|
||||
public T Get<T>(string key)
|
||||
{
|
||||
return Data.ContainsKey(key) ? (T)Data[key] : default;
|
||||
}
|
||||
}
|
||||
|
||||
public interface INode
|
||||
{
|
||||
Context Enter(Context context);
|
||||
Context Exit(Context context);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public partial class ConditionNode : INode
|
||||
{
|
||||
public Func<Context, bool> Condition { get; set; }
|
||||
public INode TrueBranch { get; set; }
|
||||
public INode FalseBranch { get; set; }
|
||||
|
||||
public Context Enter(Context context)
|
||||
{
|
||||
if (Condition(context))
|
||||
{
|
||||
return TrueBranch?.Enter(context) ?? context;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FalseBranch?.Enter(context) ?? context;
|
||||
}
|
||||
}
|
||||
|
||||
public Context Exit(Context context)
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public partial class ActionNode : INode
|
||||
{
|
||||
public Action<Context> Action { get; set; }
|
||||
public bool IsTask { get; set; }
|
||||
|
||||
public Context Enter(Context context)
|
||||
{
|
||||
if (IsTask)
|
||||
{
|
||||
Task.Run(() => Action(context));
|
||||
}
|
||||
else
|
||||
{
|
||||
Action(context);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
public Context Exit(Context context)
|
||||
{
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class StateNode : INode
|
||||
{
|
||||
public Context Enter(Context context)
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
public Context Exit(Context context)
|
||||
{
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
*/
|
||||
@@ -40,6 +40,11 @@ namespace Serein.WorkBench.Themes
|
||||
TypeTreeView.Items.Add(rootNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加属性节点
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
/// <param name="type"></param>
|
||||
private void AddMembersToTreeNode(TreeViewItem node, Type type)
|
||||
{
|
||||
var members = type.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
|
||||
@@ -61,6 +66,7 @@ namespace Serein.WorkBench.Themes
|
||||
memberNode.Header = $"{member.Name} : {propertyType.Name}";
|
||||
if (!propertyType.IsPrimitive && propertyType != typeof(string))
|
||||
{
|
||||
// 递归显示类型属性的节点
|
||||
AddMembersToTreeNode(memberNode, propertyType);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user