mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
1. 重新设计了Generate项目及相关特性的命名,避免与其他类型混淆。
2. 补充了部分注释。 3. 修改了删除容器节点时,容器内子节点未正确删除的问题。
This commit is contained in:
@@ -7,6 +7,11 @@
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
public interface IEnumConvertor<TEnum, TValue>
|
||||
{
|
||||
/// <summary>
|
||||
/// 将枚举值转换为指定类型的值
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
/// <returns></returns>
|
||||
TValue Convertor(TEnum e);
|
||||
}
|
||||
|
||||
|
||||
@@ -252,11 +252,20 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
public string Result { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上传当前节点的执行状态和结果信息。
|
||||
/// </summary>
|
||||
/// <param name="runState"></param>
|
||||
public void UploadState(RunState runState)
|
||||
{
|
||||
State = runState;
|
||||
TS = DateTime.Now - StateTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上传当前节点的执行结果值。
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void UploadResultValue(object value = null)
|
||||
{
|
||||
if(value is null)
|
||||
@@ -269,6 +278,11 @@ namespace Serein.Library.Api
|
||||
Result = $"{type.FullName}::{value}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上传当前节点的执行参数信息。
|
||||
/// </summary>
|
||||
/// <param name="values"></param>
|
||||
public void UploadParameters(object[] values = null)
|
||||
{
|
||||
if (values is null)
|
||||
@@ -282,6 +296,10 @@ namespace Serein.Library.Api
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回当前节点的执行信息字符串,包含状态、耗时和结果。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[{State}]{TS.TotalSeconds:0.000}ms : {Result}";
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Api
|
||||
{
|
||||
#nullable enable
|
||||
/// <summary>
|
||||
/// 流程运行接口
|
||||
/// </summary>
|
||||
@@ -24,7 +25,7 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
/// <param name="ioc"></param>
|
||||
/// <param name="setDefultMemberOnReset">用于每次启动时,重置IOC后默认注册某些类型</param>
|
||||
void UseExternalIOC(ISereinIOC ioc, Action<ISereinIOC> setDefultMemberOnReset = null);
|
||||
void UseExternalIOC(ISereinIOC ioc, Action<ISereinIOC>? setDefultMemberOnReset = null);
|
||||
|
||||
/// <summary>
|
||||
/// 开始运行流程
|
||||
|
||||
@@ -153,6 +153,9 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
public class ProjectLoadedEventArgs : FlowEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 项目加载完成事件参数
|
||||
/// </summary>
|
||||
public ProjectLoadedEventArgs()
|
||||
{
|
||||
}
|
||||
@@ -163,6 +166,10 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
public class ProjectSavingEventArgs : FlowEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 项目保存事件参数
|
||||
/// </summary>
|
||||
/// <param name="projectData"></param>
|
||||
public ProjectSavingEventArgs(SereinProjectData projectData)
|
||||
{
|
||||
ProjectData = projectData;
|
||||
@@ -179,6 +186,10 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
public class LoadDllEventArgs : FlowEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载了DLL外部依赖事件参数
|
||||
/// </summary>
|
||||
/// <param name="nodeLibraryInfo"></param>
|
||||
public LoadDllEventArgs(FlowLibraryInfo nodeLibraryInfo)
|
||||
{
|
||||
this.NodeLibraryInfo = nodeLibraryInfo;
|
||||
@@ -194,6 +205,9 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
public class RemoteDllEventArgs : FlowEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 移除了DLL外部依赖事件参数
|
||||
/// </summary>
|
||||
public RemoteDllEventArgs()
|
||||
{
|
||||
}
|
||||
@@ -270,6 +284,9 @@ namespace Serein.Library.Api
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接关系所在的画布Guid
|
||||
/// </summary>
|
||||
public string CanvasGuid { get; }
|
||||
|
||||
/// <summary>
|
||||
@@ -309,11 +326,18 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
public class CanvasCreateEventArgs : FlowEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 画布添加事件参数
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
public CanvasCreateEventArgs(FlowCanvasDetails model)
|
||||
{
|
||||
Model = model;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 画布
|
||||
/// </summary>
|
||||
public FlowCanvasDetails Model { get; }
|
||||
}
|
||||
|
||||
@@ -322,11 +346,18 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
public class CanvasRemoveEventArgs : FlowEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 画布移除事件参数
|
||||
/// </summary>
|
||||
/// <param name="canvasGuid"></param>
|
||||
public CanvasRemoveEventArgs(string canvasGuid)
|
||||
{
|
||||
CanvasGuid = canvasGuid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 所处画布Guid
|
||||
/// </summary>
|
||||
public string CanvasGuid { get; }
|
||||
}
|
||||
|
||||
@@ -360,10 +391,6 @@ namespace Serein.Library.Api
|
||||
/// 在UI上的位置
|
||||
/// </summary>
|
||||
public PositionOfUI Position { get; private set; }
|
||||
/// <summary>
|
||||
/// 容器
|
||||
/// </summary>
|
||||
//public string RegeionGuid { get; private set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -371,12 +398,20 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
public class NodeRemoveEventArgs : FlowEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 被移除节点事件参数
|
||||
/// </summary>
|
||||
/// <param name="canvasGuid"></param>
|
||||
/// <param name="nodeGuid"></param>
|
||||
public NodeRemoveEventArgs(string canvasGuid, string nodeGuid)
|
||||
{
|
||||
CanvasGuid = canvasGuid;
|
||||
this.NodeGuid = nodeGuid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 被移除节点所在的画布Guid
|
||||
/// </summary>
|
||||
public string CanvasGuid { get; }
|
||||
|
||||
/// <summary>
|
||||
@@ -390,6 +425,12 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
public class NodePlaceEventArgs : FlowEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 节点放置事件参数
|
||||
/// </summary>
|
||||
/// <param name="canvasGuid"></param>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <param name="containerNodeGuid"></param>
|
||||
public NodePlaceEventArgs(string canvasGuid, string nodeGuid, string containerNodeGuid)
|
||||
{
|
||||
CanvasGuid = canvasGuid;
|
||||
@@ -397,6 +438,9 @@ namespace Serein.Library.Api
|
||||
ContainerNodeGuid = containerNodeGuid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 画布Guid
|
||||
/// </summary>
|
||||
public string CanvasGuid { get; }
|
||||
|
||||
/// <summary>
|
||||
@@ -414,6 +458,12 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
public class NodeTakeOutEventArgs : FlowEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 节点取出事件参数
|
||||
/// </summary>
|
||||
/// <param name="canvasGuid"></param>
|
||||
/// <param name="containerNodeGuid"></param>
|
||||
/// <param name="nodeGuid"></param>
|
||||
public NodeTakeOutEventArgs(string canvasGuid, string containerNodeGuid, string nodeGuid)
|
||||
{
|
||||
CanvasGuid = canvasGuid;
|
||||
@@ -421,6 +471,9 @@ namespace Serein.Library.Api
|
||||
ContainerNodeGuid = containerNodeGuid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 所在画布Guid
|
||||
/// </summary>
|
||||
public string CanvasGuid { get; }
|
||||
|
||||
/// <summary>
|
||||
@@ -438,9 +491,17 @@ namespace Serein.Library.Api
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 起始节点发生了变化
|
||||
/// </summary>
|
||||
public class StartNodeChangeEventArgs : FlowEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 起始节点发生了变化事件参数
|
||||
/// </summary>
|
||||
/// <param name="canvasGuid"></param>
|
||||
/// <param name="oldNodeGuid"></param>
|
||||
/// <param name="newNodeGuid"></param>
|
||||
public StartNodeChangeEventArgs(string canvasGuid, string oldNodeGuid, string newNodeGuid)
|
||||
{
|
||||
CanvasGuid = canvasGuid;
|
||||
@@ -448,6 +509,9 @@ namespace Serein.Library.Api
|
||||
this.NewNodeGuid = newNodeGuid; ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 所在画布Guid
|
||||
/// </summary>
|
||||
public string CanvasGuid { get; }
|
||||
|
||||
/// <summary>
|
||||
@@ -515,6 +579,11 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
public class NodeInterruptStateChangeEventArgs : FlowEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 节点中断状态改变事件参数
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <param name="isInterrupt"></param>
|
||||
public NodeInterruptStateChangeEventArgs(string nodeGuid,bool isInterrupt)
|
||||
{
|
||||
NodeGuid = nodeGuid;
|
||||
@@ -526,14 +595,19 @@ namespace Serein.Library.Api
|
||||
/// 中断的节点Guid
|
||||
/// </summary>
|
||||
public string NodeGuid { get;}
|
||||
/// <summary>
|
||||
/// 是否中断
|
||||
/// </summary>
|
||||
public bool IsInterrupt { get;}
|
||||
// public InterruptClass Class { get;}
|
||||
}
|
||||
/// <summary>
|
||||
/// 节点触发了中断事件参数
|
||||
/// </summary>
|
||||
public class InterruptTriggerEventArgs : FlowEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 中断触发类型
|
||||
/// </summary>
|
||||
public enum InterruptTriggerType
|
||||
{
|
||||
/// <summary>
|
||||
@@ -550,6 +624,12 @@ namespace Serein.Library.Api
|
||||
Obj,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 中断触发事件参数
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <param name="expression"></param>
|
||||
/// <param name="type"></param>
|
||||
public InterruptTriggerEventArgs(string nodeGuid, string expression, InterruptTriggerType type)
|
||||
{
|
||||
this.NodeGuid = nodeGuid;
|
||||
@@ -561,7 +641,13 @@ namespace Serein.Library.Api
|
||||
/// 中断的节点Guid
|
||||
/// </summary>
|
||||
public string NodeGuid { get;}
|
||||
/// <summary>
|
||||
/// 被触发的表达式
|
||||
/// </summary>
|
||||
public string Expression { get;}
|
||||
/// <summary>
|
||||
/// 中断触发类型
|
||||
/// </summary>
|
||||
public InterruptTriggerType Type { get;}
|
||||
}
|
||||
|
||||
@@ -572,6 +658,9 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
public class IOCMembersChangedEventArgs : FlowEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// IOC成员发生改变的事件类型
|
||||
/// </summary>
|
||||
public enum EventType
|
||||
{
|
||||
/// <summary>
|
||||
@@ -583,12 +672,23 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
Completeuild,
|
||||
}
|
||||
/// <summary>
|
||||
/// IOC成员发生改变事件参数
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="instance"></param>
|
||||
public IOCMembersChangedEventArgs(string key, object instance)
|
||||
{
|
||||
this.Key = key;
|
||||
this.Instance = instance;
|
||||
}
|
||||
/// <summary>
|
||||
/// IOC成员发生改变事件参数
|
||||
/// </summary>
|
||||
public string Key { get; private set; }
|
||||
/// <summary>
|
||||
/// IOC成员发生改变事件参数
|
||||
/// </summary>
|
||||
public object Instance { get; private set; }
|
||||
}
|
||||
|
||||
@@ -597,38 +697,20 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
public class NodeLocatedEventArgs : FlowEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 节点需要定位事件参数
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
public NodeLocatedEventArgs(string nodeGuid)
|
||||
{
|
||||
NodeGuid = nodeGuid;
|
||||
}
|
||||
/// <summary>
|
||||
/// 节点需要定位事件参数
|
||||
/// </summary>
|
||||
public string NodeGuid { get; private set; }
|
||||
}
|
||||
|
||||
/* /// <summary>
|
||||
/// 节点移动了
|
||||
/// </summary>
|
||||
public class NodeMovedEventArgs : FlowEventArgs
|
||||
{
|
||||
public NodeMovedEventArgs(string nodeGuid, double x, double y)
|
||||
{
|
||||
this.NodeGuid = nodeGuid;
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
}
|
||||
/// <summary>
|
||||
/// 节点唯一标识
|
||||
/// </summary>
|
||||
public string NodeGuid { get; private set; }
|
||||
/// <summary>
|
||||
/// 画布上的x坐标
|
||||
/// </summary>
|
||||
public double X { get; private set; }
|
||||
/// <summary>
|
||||
/// 画布上的y坐标
|
||||
/// </summary>
|
||||
public double Y { get; private set; }
|
||||
}*/
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -729,23 +811,113 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
event EnvOutHandler EnvOutput;
|
||||
|
||||
/// <summary>
|
||||
/// 加载了DLL外部依赖事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public void OnDllLoad(LoadDllEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 项目加载完成事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public void OnProjectLoaded(ProjectLoadedEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 项目准备保存事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public void OnProjectSaving(ProjectSavingEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 节点连接关系发生改变事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public void OnNodeConnectChanged(NodeConnectChangeEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 画布创建事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public void OnCanvasCreated(CanvasCreateEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 画布移除事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public void OnCanvasRemoved(CanvasRemoveEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 节点创建事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public void OnNodeCreated(NodeCreateEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 节点移除事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public void OnNodeRemoved(NodeRemoveEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 节点放置事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public void OnNodePlace(NodePlaceEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 节点取出事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public void OnNodeTakeOut(NodeTakeOutEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 起始节点发生了变化事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public void OnStartNodeChanged(StartNodeChangeEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 流程运行完成事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public void OnFlowRunComplete(FlowEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 被监视的对象发生了改变事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public void OnMonitorObjectChanged(MonitorObjectEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 节点中断状态发生了改变事件(开启了中断/取消了中断)
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public void OnNodeInterruptStateChanged(NodeInterruptStateChangeEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 触发了中断事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public void OnInterruptTriggered(InterruptTriggerEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// IOC容器成员发生了改变事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public void OnIOCMembersChanged(IOCMembersChangedEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 节点需要定位事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public void OnNodeLocated(NodeLocatedEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// 环境输出信息事件
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="value"></param>
|
||||
public void OnEnvOutput(InfoType type, string value);
|
||||
}
|
||||
|
||||
@@ -864,7 +1036,7 @@ namespace Serein.Library.Api
|
||||
/// 获取当前项目信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<SereinProjectData> GetProjectInfoAsync();
|
||||
SereinProjectData GetProjectInfoAsync();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading.Tasks;
|
||||
using Serein.Library;
|
||||
|
||||
namespace Serein.Library.Api
|
||||
{
|
||||
@@ -72,11 +67,11 @@ namespace Serein.Library.Api
|
||||
MethodDetails MethodDetails { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 父节点集合
|
||||
/// 前继节点集合
|
||||
/// </summary>
|
||||
Dictionary<ConnectionInvokeType, List<IFlowNode>> PreviousNodes { get;}
|
||||
/// <summary>
|
||||
/// 子节点集合
|
||||
/// 后继节点集合
|
||||
/// </summary>
|
||||
Dictionary<ConnectionInvokeType, List<IFlowNode>> SuccessorNodes { get; set; }
|
||||
|
||||
|
||||
@@ -118,14 +118,14 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
/// <param name="values"></param>
|
||||
/// <returns></returns>
|
||||
IJsonToken CreateObject(IDictionary<string, object> values = null);
|
||||
IJsonToken CreateObject(IDictionary<string, object>? values = null);
|
||||
|
||||
/// <summary>
|
||||
/// 创建数组
|
||||
/// </summary>
|
||||
/// <param name="values"></param>
|
||||
/// <returns></returns>
|
||||
IJsonToken CreateArray(IEnumerable<object> values = null);
|
||||
IJsonToken CreateArray(IEnumerable<object>? values = null);
|
||||
|
||||
/// <summary>
|
||||
/// 将对象转换为JSON Token,自动转换为 JObject/JArray。
|
||||
|
||||
@@ -11,7 +11,9 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
public interface INodeContainer
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 容器节点的Guid,与 IFlowNode.Guid 相同
|
||||
/// </summary>
|
||||
string Guid { get; }
|
||||
/// <summary>
|
||||
/// 放置一个节点
|
||||
|
||||
@@ -20,20 +20,7 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
IFlowNode NodeModel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 根据索引从入参数据获取数据
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
//object GetArgData(IDynamicContext context, int index);
|
||||
/// <summary>
|
||||
/// 获取流程当前传递的数据
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
/// FlowResult GetFlowData(IDynamicContext context);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取全局数据
|
||||
/// </summary>
|
||||
|
||||
@@ -108,8 +108,32 @@ namespace Serein.Library.Api
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
ISereinIOC Run<T>(Action<T> action);
|
||||
/// <summary>
|
||||
/// 从容器中获取数个类型的实例进行运行
|
||||
/// </summary>
|
||||
/// <typeparam name="T1"></typeparam>
|
||||
/// <typeparam name="T2"></typeparam>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
ISereinIOC Run<T1, T2>(Action<T1, T2> action);
|
||||
/// <summary>
|
||||
/// 从容器中获取数个类型的实例进行运行
|
||||
/// </summary>
|
||||
/// <typeparam name="T1"></typeparam>
|
||||
/// <typeparam name="T2"></typeparam>
|
||||
/// <typeparam name="T3"></typeparam>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
ISereinIOC Run<T1, T2, T3>(Action<T1, T2, T3> action);
|
||||
/// <summary>
|
||||
/// 从容器中获取数个类型的实例进行运行
|
||||
/// </summary>
|
||||
/// <typeparam name="T1"></typeparam>
|
||||
/// <typeparam name="T2"></typeparam>
|
||||
/// <typeparam name="T3"></typeparam>
|
||||
/// <typeparam name="T4"></typeparam>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
ISereinIOC Run<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action);
|
||||
|
||||
}
|
||||
|
||||
@@ -16,10 +16,17 @@ namespace Serein.Library
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public sealed class AutoRegisterAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 自动注册特性
|
||||
/// </summary>
|
||||
/// <param name="Class"></param>
|
||||
public AutoRegisterAttribute(RegisterSequence Class = RegisterSequence.FlowInit)
|
||||
{
|
||||
this.Class = Class;
|
||||
}
|
||||
/// <summary>
|
||||
/// 注册顺序
|
||||
/// </summary>
|
||||
public RegisterSequence Class ;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,9 +8,20 @@ namespace Serein.Library
|
||||
[AttributeUsage(AttributeTargets.Parameter)]
|
||||
public class BindConvertorAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 枚举类型
|
||||
/// </summary>
|
||||
public Type EnumType { get; }
|
||||
/// <summary>
|
||||
/// 转换器类型
|
||||
/// </summary>
|
||||
public Type ConvertorType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 绑定转换器特性
|
||||
/// </summary>
|
||||
/// <param name="enum"></param>
|
||||
/// <param name="convertor"></param>
|
||||
public BindConvertorAttribute(Type @enum, Type convertor)
|
||||
{
|
||||
EnumType = @enum;
|
||||
|
||||
@@ -2,11 +2,21 @@
|
||||
|
||||
namespace Serein.Library
|
||||
{
|
||||
/// <summary>
|
||||
/// 绑定值特性
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class BindValueAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 绑定的值
|
||||
/// </summary>
|
||||
public object Value { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 绑定值特性构造函数
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public BindValueAttribute(object value)
|
||||
{
|
||||
Value = value;
|
||||
|
||||
@@ -10,6 +10,11 @@ namespace Serein.Library
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public sealed class DynamicFlowAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 动态流程特性构造函数
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="scan"></param>
|
||||
public DynamicFlowAttribute(string name = "",bool scan = true)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
@@ -9,8 +9,16 @@ namespace Serein.Library
|
||||
[AttributeUsage(AttributeTargets.Parameter)]
|
||||
public class EnumTypeConvertorAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 枚举类型
|
||||
/// </summary>
|
||||
public Type EnumType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 枚举类型转换器特性构造函数
|
||||
/// </summary>
|
||||
/// <param name="enum"></param>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public EnumTypeConvertorAttribute(Type @enum)
|
||||
{
|
||||
if (@enum.IsEnum)
|
||||
|
||||
@@ -9,6 +9,13 @@ namespace Serein.Library
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||
public sealed class NodeActionAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 节点行为特性构造函数
|
||||
/// </summary>
|
||||
/// <param name="methodDynamicType"></param>
|
||||
/// <param name="methodTips"></param>
|
||||
/// <param name="scan"></param>
|
||||
/// <param name="lockName"></param>
|
||||
public NodeActionAttribute(NodeType methodDynamicType,
|
||||
string methodTips = "",
|
||||
bool scan = true,
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Serein.Library
|
||||
|
||||
/// <summary>
|
||||
/// 表示了两个节点之间的连接关系,同时表示节点运行完成后,所会执行的下一个节点类型。
|
||||
/// </summary
|
||||
/// </summary>
|
||||
public enum ConnectionInvokeType
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -6,9 +6,18 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library
|
||||
{
|
||||
/// <summary>
|
||||
/// 参数值输入类型
|
||||
/// </summary>
|
||||
public enum ParameterValueInputType
|
||||
{
|
||||
/// <summary>
|
||||
/// 参数值输入类型 - 输入
|
||||
/// </summary>
|
||||
Input,
|
||||
/// <summary>
|
||||
/// 参数值输入类型 - 选择器(枚举类型)
|
||||
/// </summary>
|
||||
Select,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@ namespace Serein.Library
|
||||
/// </summary>
|
||||
public class FlipflopException: Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// 触发器取消类型
|
||||
/// </summary>
|
||||
public enum CancelClass
|
||||
{
|
||||
/// <summary>
|
||||
@@ -27,6 +30,13 @@ namespace Serein.Library
|
||||
/// 取消类型
|
||||
/// </summary>
|
||||
public CancelClass Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 触发器异常构造函数
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="isCancel"></param>
|
||||
/// <param name="clsss"></param>
|
||||
public FlipflopException(string message, bool isCancel = true,CancelClass clsss = CancelClass.CancelBranch) :base(message)
|
||||
{
|
||||
IsCancel = isCancel;
|
||||
|
||||
@@ -11,10 +11,23 @@ namespace Serein.Library
|
||||
[DynamicFlow(Name ="[基础功能]")]
|
||||
public static class FlowBaseLibrary
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 对象透传,直接返回入参的值
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
[NodeAction(NodeType.Action, "对象透传")]
|
||||
public static object TransmissionObject(object value) => value;
|
||||
|
||||
/// <summary>
|
||||
/// 键值对组装,将入参的值与名称组装成一个字典对象
|
||||
/// </summary>
|
||||
/// <param name="argNames"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
|
||||
[NodeAction(NodeType.Action, "键值对组装")]
|
||||
public static Dictionary<string, object> DictSet(string argNames, params object[] value)
|
||||
{
|
||||
@@ -32,12 +45,22 @@ namespace Serein.Library
|
||||
return dict;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数组组装,将入参的值组装成一个数组对象
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
[NodeAction(NodeType.Action, "数组组装")]
|
||||
public static object[] ArraySet(params object[] value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出到控制台,使用SereinEnv.WriteLine方法输出信息
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
[NodeAction(NodeType.Action, "输出")]
|
||||
public static object[] Console(params object[] value)
|
||||
{
|
||||
@@ -48,7 +71,14 @@ namespace Serein.Library
|
||||
return value;
|
||||
}
|
||||
|
||||
[NodeAction(NodeType.Action, "逻辑分支")]
|
||||
/// <summary>
|
||||
/// 逻辑分支,根据布尔值选择返回的值,如果布尔值为true则返回t_value,否则返回f_value
|
||||
/// </summary>
|
||||
/// <param name="bool"></param>
|
||||
/// <param name="t_value"></param>
|
||||
/// <param name="f_value"></param>
|
||||
/// <returns></returns>
|
||||
[NodeAction(NodeType.Action, "逻辑选择")]
|
||||
public static object LogicalBranch([NodeParam(IsExplicit = false)]bool @bool,
|
||||
object t_value,
|
||||
object f_value)
|
||||
@@ -56,6 +86,12 @@ namespace Serein.Library
|
||||
return @bool ? t_value : f_value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文本拼接,将多个文本值拼接成一个字符串,支持换行符和制表符的特殊处理
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
[NodeAction(NodeType.Action, "文本拼接")]
|
||||
public static string TextJoin(params object[] value)
|
||||
{
|
||||
@@ -79,6 +115,13 @@ namespace Serein.Library
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 动态构建对象,将字典中的键值对转换为一个动态对象,支持指定类名和打印结果
|
||||
/// </summary>
|
||||
/// <param name="dict"></param>
|
||||
/// <param name="classTypeName"></param>
|
||||
/// <param name="IsPrint"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
[NodeAction(NodeType.Action, "键值对动态构建对象")]
|
||||
public static object CreateDynamicObjectOfDict(Dictionary<string, object> dict,
|
||||
@@ -100,13 +143,5 @@ namespace Serein.Library
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
[NodeAction(NodeType.Action, "设置或更新全局数据")]
|
||||
public static object AddOrUpdateFlowGlobalData(string name, object data)
|
||||
{
|
||||
SereinEnv.AddOrUpdateFlowGlobalData(name, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,9 +57,18 @@ namespace Serein.Library
|
||||
CollectionSetter
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示方法的类型
|
||||
/// </summary>
|
||||
public enum GSType
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取值
|
||||
/// </summary>
|
||||
Get,
|
||||
/// <summary>
|
||||
/// 设置值
|
||||
/// </summary>
|
||||
Set,
|
||||
}
|
||||
|
||||
@@ -149,7 +158,7 @@ namespace Serein.Library
|
||||
/// 目前提供了创建集合取值/赋值委托
|
||||
/// </summary>
|
||||
/// <param name="type">类型信息</param>
|
||||
/// <param name="gsType">操作类型</param>
|
||||
/// <param name="emitType">操作类型</param>
|
||||
public DelegateDetails(Type type, EmitType emitType)
|
||||
{
|
||||
if (emitType == EmitType.CollectionSetter)
|
||||
|
||||
@@ -5,6 +5,9 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library
|
||||
{
|
||||
/// <summary>
|
||||
/// FlipflopFunc 类提供了与 Flipflop 相关的功能方法。
|
||||
/// </summary>
|
||||
public static class FlipflopFunc
|
||||
{
|
||||
/// <summary>
|
||||
@@ -72,15 +75,34 @@ namespace Serein.Library
|
||||
/// </summary>
|
||||
public class FlipflopContext<TResult> : IFlipflopContext<TResult>
|
||||
{
|
||||
/// <summary>
|
||||
/// 触发器完成的状态(根据业务场景手动设置)
|
||||
/// </summary>
|
||||
public FlipflopStateType State { get; set; }
|
||||
/// <summary>
|
||||
/// 触发类型
|
||||
/// </summary>
|
||||
|
||||
public TriggerDescription Type { get; set; }
|
||||
/// <summary>
|
||||
/// 触发时传递的数据
|
||||
/// </summary>
|
||||
public TResult Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 触发器上下文构造函数
|
||||
/// </summary>
|
||||
/// <param name="ffState"></param>
|
||||
public FlipflopContext(FlipflopStateType ffState)
|
||||
{
|
||||
State = ffState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 触发器上下文构造函数,传入状态和数据值
|
||||
/// </summary>
|
||||
/// <param name="ffState"></param>
|
||||
/// <param name="value"></param>
|
||||
public FlipflopContext(FlipflopStateType ffState, TResult value)
|
||||
{
|
||||
State = ffState;
|
||||
|
||||
@@ -16,81 +16,88 @@ namespace Serein.Library
|
||||
/// <summary>
|
||||
/// 流程画布
|
||||
/// </summary>
|
||||
[NodeProperty(ValuePath = NodeValuePath.Node)]
|
||||
[FlowDataProperty(ValuePath = NodeValuePath.Node)]
|
||||
public partial class FlowCanvasDetails
|
||||
{
|
||||
/// <summary>
|
||||
/// 流程画布的构造函数
|
||||
/// </summary>
|
||||
/// <param name="env"></param>
|
||||
public FlowCanvasDetails(IFlowEnvironment env)
|
||||
{
|
||||
Env = env;
|
||||
}
|
||||
/// <summary>
|
||||
/// 流程画布的运行环境
|
||||
/// </summary>
|
||||
|
||||
public IFlowEnvironment Env { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 画布拥有的节点
|
||||
/// </summary>
|
||||
[PropertyInfo(IsProtection = false)]
|
||||
[DataInfo(IsProtection = false)]
|
||||
private List<IFlowNode> _nodes = [];
|
||||
//private System.Collections.ObjectModel.ObservableCollection<IFlowNode> _nodes = [];
|
||||
|
||||
/// <summary>
|
||||
/// 画布公开的节点
|
||||
/// </summary>
|
||||
[PropertyInfo(IsProtection = false)]
|
||||
[DataInfo(IsProtection = false)]
|
||||
private List<IFlowNode> _publicNodes = [];
|
||||
|
||||
/// <summary>
|
||||
/// 标识画布ID
|
||||
/// </summary>
|
||||
[PropertyInfo(IsProtection = false)]
|
||||
[DataInfo(IsProtection = false)]
|
||||
private string _guid;
|
||||
|
||||
/// <summary>
|
||||
/// 画布名称
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true)]
|
||||
[DataInfo(IsNotification = true)]
|
||||
private string _name;
|
||||
|
||||
/// <summary>
|
||||
/// 画布宽度
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true)]
|
||||
[DataInfo(IsNotification = true)]
|
||||
private double _width;
|
||||
|
||||
/// <summary>
|
||||
/// 画布高度
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true)]
|
||||
[DataInfo(IsNotification = true)]
|
||||
private double _height;
|
||||
|
||||
/// <summary>
|
||||
/// 预览位置X
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true)]
|
||||
[DataInfo(IsNotification = true)]
|
||||
private double _viewX;
|
||||
|
||||
/// <summary>
|
||||
/// 预览位置Y
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true)]
|
||||
[DataInfo(IsNotification = true)]
|
||||
private double _viewY;
|
||||
|
||||
/// <summary>
|
||||
/// 缩放比例X
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true)]
|
||||
[DataInfo(IsNotification = true)]
|
||||
private double _scaleX = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 缩放比例Y
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true)]
|
||||
[DataInfo(IsNotification = true)]
|
||||
private double _scaleY = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 起始节点
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private IFlowNode _startNode;
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace Serein.Library
|
||||
/// 动态流程上下文
|
||||
/// </summary>
|
||||
/// <param name="flowEnvironment">脚本运行时的IOC</param>
|
||||
/// <param name="ioc">脚本运行时使用的IOC容器</param>
|
||||
public FlowContext(IFlowEnvironment flowEnvironment)
|
||||
{
|
||||
Env = flowEnvironment;
|
||||
@@ -110,6 +109,10 @@ namespace Serein.Library
|
||||
return flowInvokeInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前流程上下文的所有节点调用信息,包含每个节点的执行时间、调用类型、执行状态等。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<FlowInvokeInfo> GetAllInvokeInfos() => [.. flowInvokeInfos.Values];
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -9,17 +9,6 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示空数据
|
||||
/// </summary>
|
||||
/*public readonly struct Unit : IEquatable<Unit>
|
||||
{
|
||||
public static readonly Unit Default = default;
|
||||
public bool Equals(Unit _) => true;
|
||||
public override bool Equals(object obj) => obj is Unit;
|
||||
public override int GetHashCode() => 0;
|
||||
}*/
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 流程返回值的包装
|
||||
|
||||
@@ -33,6 +33,11 @@ namespace Serein.Library.FlowNode
|
||||
/// </summary>
|
||||
public class JunctionModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 连接点模型构造函数
|
||||
/// </summary>
|
||||
/// <param name="NodeModel"></param>
|
||||
/// <param name="JunctionType"></param>
|
||||
public JunctionModel(IFlowNode NodeModel, JunctionType JunctionType)
|
||||
{
|
||||
Guid = System.Guid.NewGuid().ToString();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -8,76 +7,21 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library
|
||||
{
|
||||
/*
|
||||
public class CallNodeLookup : IFlowCallTree
|
||||
{
|
||||
private static readonly string[] _keys = new[]
|
||||
{
|
||||
"Start", // 0
|
||||
"Stop", // 1
|
||||
"Reset", // 2
|
||||
"Pause", // 3
|
||||
"Resume", // 4
|
||||
"Check", // 5
|
||||
"Init", // 6
|
||||
"Load", // 7
|
||||
"Save", // 8
|
||||
"Clear" // 9
|
||||
};
|
||||
|
||||
private static readonly CallNode[] _values = new CallNode[10];
|
||||
|
||||
static CallNodeLookup()
|
||||
{
|
||||
*//*_values[0] = new CallNode("Start");
|
||||
_values[1] = new CallNode("Stop");
|
||||
_values[2] = new CallNode("Reset");
|
||||
_values[3] = new CallNode("Pause");
|
||||
_values[4] = new CallNode("Resume");
|
||||
_values[5] = new CallNode("Check");
|
||||
_values[6] = new CallNode("Init");
|
||||
_values[7] = new CallNode("Load");
|
||||
_values[8] = new CallNode("Save");
|
||||
_values[9] = new CallNode("Clear");*//*
|
||||
}
|
||||
|
||||
// 最小冲突哈希函数(简单示例,固定键集有效)
|
||||
private static int PerfectHash(string key)
|
||||
{
|
||||
return key switch
|
||||
{
|
||||
"Start" => 0,
|
||||
"Stop" => 1,
|
||||
"Reset" => 2,
|
||||
"Pause" => 3,
|
||||
"Resume" => 4,
|
||||
"Check" => 5,
|
||||
"Init" => 6,
|
||||
"Load" => 7,
|
||||
"Save" => 8,
|
||||
"Clear" => 9,
|
||||
_ => -1
|
||||
};
|
||||
}
|
||||
|
||||
public CallNode Get(string key)
|
||||
{
|
||||
int index = PerfectHash(key);
|
||||
if (index >= 0 && _keys[index] == key)
|
||||
return _values[index];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// 流程调用树,管理所有的调用节点
|
||||
/// </summary>
|
||||
public class FlowCallTree : IFlowCallTree
|
||||
{
|
||||
|
||||
private readonly SortedDictionary<string, CallNode> _callNodes = new SortedDictionary<string,CallNode>();
|
||||
//private readonly Dictionary<string, CallNode> _callNodes = new Dictionary<string,CallNode>();
|
||||
|
||||
/// <summary>
|
||||
/// 索引器,允许通过字符串索引访问CallNode
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public CallNode this[string index]
|
||||
{
|
||||
get
|
||||
@@ -92,17 +36,33 @@ namespace Serein.Library
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个调用节点到流程调用树中
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <param name="action"></param>
|
||||
public void AddCallNode(string nodeGuid, Action<IFlowContext> action)
|
||||
{
|
||||
var node = new CallNode(nodeGuid, action);
|
||||
_callNodes[nodeGuid] = node;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个调用节点到流程调用树中,使用异步函数
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <param name="func"></param>
|
||||
public void AddCallNode(string nodeGuid, Func<IFlowContext, Task> func)
|
||||
{
|
||||
var node = new CallNode(nodeGuid, func);
|
||||
_callNodes[nodeGuid] = node;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定Key的CallNode,如果不存在则返回null
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public CallNode Get(string key)
|
||||
{
|
||||
return _callNodes.TryGetValue(key, out CallNode callNode) ? callNode : null;
|
||||
@@ -112,7 +72,9 @@ namespace Serein.Library
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 调用节点,代表一个流程中的调用点,可以是一个Action或一个异步函数。
|
||||
/// </summary>
|
||||
|
||||
public class CallNode
|
||||
{
|
||||
@@ -120,11 +82,21 @@ namespace Serein.Library
|
||||
private Func<IFlowContext, Task> taskFunc;
|
||||
private Action<IFlowContext> action;
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的调用节点,使用指定的节点Guid。
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
public CallNode(string nodeGuid)
|
||||
{
|
||||
Guid = nodeGuid;
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的调用节点,使用指定的节点Guid和Action。
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <param name="action"></param>
|
||||
public CallNode(string nodeGuid, Action<IFlowContext> action)
|
||||
{
|
||||
Guid = nodeGuid;
|
||||
@@ -132,6 +104,11 @@ namespace Serein.Library
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的调用节点,使用指定的节点Guid和异步函数。
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <param name="func"></param>
|
||||
public CallNode(string nodeGuid, Func<IFlowContext, Task> func)
|
||||
{
|
||||
Guid = nodeGuid;
|
||||
@@ -139,7 +116,9 @@ namespace Serein.Library
|
||||
Init();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 初始化调用节点,设置默认的子节点和后继节点字典。
|
||||
/// </summary>
|
||||
private void Init()
|
||||
{
|
||||
//PreviousNodes = new Dictionary<ConnectionInvokeType, List<CallNode>>();
|
||||
@@ -151,17 +130,28 @@ namespace Serein.Library
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private enum ActionType
|
||||
{
|
||||
Action,
|
||||
Task,
|
||||
}
|
||||
private ActionType actionType = ActionType.Action;
|
||||
|
||||
/// <summary>
|
||||
/// 设置调用节点的Action,表示该节点执行一个同步操作。
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
public void SetAction(Action<IFlowContext> action)
|
||||
{
|
||||
this.action = action;
|
||||
actionType = ActionType.Action;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置调用节点的异步函数,表示该节点执行一个异步操作。
|
||||
/// </summary>
|
||||
/// <param name="taskFunc"></param>
|
||||
public void SetAction(Func<IFlowContext, Task> taskFunc)
|
||||
{
|
||||
this.taskFunc = taskFunc;
|
||||
@@ -173,15 +163,23 @@ namespace Serein.Library
|
||||
/// 对应的节点
|
||||
/// </summary>
|
||||
public string Guid { get; }
|
||||
|
||||
#if false
|
||||
|
||||
/// <summary>
|
||||
/// 不同分支的父节点(流程调用)
|
||||
/// </summary>
|
||||
//public Dictionary<ConnectionInvokeType, List<CallNode>> PreviousNodes { get; private set; }
|
||||
public Dictionary<ConnectionInvokeType, List<CallNode>> PreviousNodes { get; private set; }
|
||||
|
||||
#endif
|
||||
/// <summary>
|
||||
/// 不同分支的子节点(流程调用)
|
||||
/// </summary>
|
||||
public Dictionary<ConnectionInvokeType, List<CallNode>> SuccessorNodes { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 子节点数组,分为四个分支:上游、成功、失败、错误,每个分支最多支持16个子节点。
|
||||
/// </summary>
|
||||
public CallNode[][] ChildNodes { get; private set; } = new CallNode[][]
|
||||
{
|
||||
new CallNode[MaxChildNodeCount],
|
||||
@@ -191,7 +189,12 @@ namespace Serein.Library
|
||||
};
|
||||
private const int MaxChildNodeCount = 16; // 每个分支最多支持16个子节点
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的子节点数量。
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public int GetCount(ConnectionInvokeType type)
|
||||
{
|
||||
if (type == ConnectionInvokeType.Upstream) return UpstreamNodeCount;
|
||||
@@ -201,11 +204,29 @@ namespace Serein.Library
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前节点的子节点数量。
|
||||
/// </summary>
|
||||
public int UpstreamNodeCount { get; private set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前节点的成功后继子节点数量。
|
||||
/// </summary>
|
||||
public int IsSuccessorNodeCount { get; private set; } = 0;
|
||||
/// <summary>
|
||||
/// 获取当前节点的失败后继子节点数量。
|
||||
/// </summary>
|
||||
public int IsFailNodeCount { get; private set; } = 0;
|
||||
/// <summary>
|
||||
/// 获取当前节点的错误后继子节点数量。
|
||||
/// </summary>
|
||||
public int IsErrorNodeCount { get; private set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个上游子节点到当前节点。
|
||||
/// </summary>
|
||||
/// <param name="callNode"></param>
|
||||
/// <returns></returns>
|
||||
public CallNode AddChildNodeUpstream(CallNode callNode)
|
||||
{
|
||||
var connectionInvokeType = ConnectionInvokeType.Upstream;
|
||||
@@ -214,6 +235,11 @@ namespace Serein.Library
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个成功后继子节点到当前节点。
|
||||
/// </summary>
|
||||
/// <param name="callNode"></param>
|
||||
/// <returns></returns>
|
||||
public CallNode AddChildNodeSucceed(CallNode callNode)
|
||||
{
|
||||
ChildNodes[0][UpstreamNodeCount++] = callNode;
|
||||
@@ -224,6 +250,11 @@ namespace Serein.Library
|
||||
|
||||
return this;
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加一个失败后继子节点到当前节点。
|
||||
/// </summary>
|
||||
/// <param name="callNode"></param>
|
||||
/// <returns></returns>
|
||||
public CallNode AddChildNodeFail(CallNode callNode)
|
||||
{
|
||||
var connectionInvokeType = ConnectionInvokeType.IsFail;
|
||||
@@ -232,6 +263,12 @@ namespace Serein.Library
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个错误后继子节点到当前节点。
|
||||
/// </summary>
|
||||
/// <param name="callNode"></param>
|
||||
/// <returns></returns>
|
||||
public CallNode AddChildNodeError(CallNode callNode)
|
||||
{
|
||||
var connectionInvokeType = ConnectionInvokeType.IsError;
|
||||
@@ -268,7 +305,7 @@ namespace Serein.Library
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly DefaultObjectPool<Stack<CallNode>> _stackPool = new DefaultObjectPool<Stack<CallNode>>(new DefaultPooledObjectPolicy<Stack<CallNode>>());
|
||||
private static readonly ObjectPool<Stack<CallNode>> _stackPool = new ObjectPool<Stack<CallNode>>(() => new Stack<CallNode>());
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -279,7 +316,7 @@ namespace Serein.Library
|
||||
/// <returns></returns>
|
||||
public async Task<FlowResult> StartFlowAsync(IFlowContext context, CancellationToken token)
|
||||
{
|
||||
var stack = _stackPool.Get();
|
||||
var stack = _stackPool.Allocate();
|
||||
stack.Push(this);
|
||||
while (true)
|
||||
{
|
||||
@@ -331,7 +368,7 @@ namespace Serein.Library
|
||||
|
||||
if (stack.Count == 0)
|
||||
{
|
||||
_stackPool.Return(stack);
|
||||
_stackPool.Free(stack);
|
||||
flowResult = context.GetFlowData(currentNode.Guid);
|
||||
return flowResult; // 说明流程到了终点
|
||||
}
|
||||
@@ -339,7 +376,7 @@ namespace Serein.Library
|
||||
if (context.RunState == RunState.Completion)
|
||||
{
|
||||
|
||||
_stackPool.Return(stack);
|
||||
_stackPool.Free(stack);
|
||||
context.Env.WriteLine(InfoType.INFO, $"流程执行到节点[{currentNode.Guid}]时提前结束,将返回当前执行结果。");
|
||||
flowResult = context.GetFlowData(currentNode.Guid);
|
||||
return flowResult; // 流程执行完成,返回结果
|
||||
@@ -347,7 +384,7 @@ namespace Serein.Library
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
{
|
||||
_stackPool.Return(stack);
|
||||
_stackPool.Free(stack);
|
||||
throw new Exception($"流程执行到节点[{currentNode.Guid}]时被取消,未能获取到流程结果。");
|
||||
}
|
||||
|
||||
@@ -359,8 +396,16 @@ namespace Serein.Library
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 流程调用树接口,提供获取CallNode的方法。
|
||||
/// </summary>
|
||||
public interface IFlowCallTree
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取指定Key的CallNode,如果不存在则返回null。
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
CallNode Get(string key);
|
||||
}
|
||||
|
||||
@@ -371,10 +416,22 @@ namespace Serein.Library
|
||||
{
|
||||
private readonly IFlowCallTree flowCallTree;
|
||||
private readonly IFlowEnvironment flowEnvironment;
|
||||
|
||||
/// <summary>
|
||||
/// 轻量级流程上下文池,使用对象池模式来管理流程上下文的创建和回收。
|
||||
/// </summary>
|
||||
public static Serein.Library.Utils.ObjectPool<IFlowContext> FlowContextPool { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 单例IOC容器,用于依赖注入和服务定位。
|
||||
/// </summary>
|
||||
public ISereinIOC IOC => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// 轻量级流程控制器构造函数,接受流程调用树和流程环境作为参数。
|
||||
/// </summary>
|
||||
/// <param name="flowCallTree"></param>
|
||||
/// <param name="flowEnvironment"></param>
|
||||
public LightweightFlowControl(IFlowCallTree flowCallTree, IFlowEnvironment flowEnvironment)
|
||||
{
|
||||
this.flowCallTree = flowCallTree;
|
||||
@@ -385,11 +442,12 @@ namespace Serein.Library
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<object> InvokeAsync(string apiGuid, Dictionary<string, object> dict)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<TResult> InvokeAsync<TResult>(string apiGuid, Dictionary<string, object> dict)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
@@ -398,7 +456,7 @@ namespace Serein.Library
|
||||
|
||||
//private readonly DefaultObjectPool<IDynamicContext> _stackPool = new DefaultObjectPool<IDynamicContext>(new DynamicContext(this));
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<TResult> StartFlowAsync<TResult>(string startNodeGuid)
|
||||
{
|
||||
IFlowContext context = Serein.Library.LightweightFlowControl.FlowContextPool.Allocate();
|
||||
@@ -443,45 +501,48 @@ namespace Serein.Library
|
||||
throw new ArgumentNullException($"类型转换失败,流程返回数据与泛型不匹配,当前返回类型为[{flowResult.Value.GetType().FullName}]。");
|
||||
}
|
||||
}
|
||||
public async Task<bool> StartFlowAsync(string[] canvasGuids)
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<bool> StartFlowAsync(string[] canvasGuids)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<bool> ExitFlowAsync()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#region 无须实现
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ActivateFlipflopNode(string nodeGuid)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void TerminateFlipflopNode(string nodeGuid)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void UseExternalIOC(ISereinIOC ioc)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void UseExternalIOC(ISereinIOC ioc, Action<ISereinIOC> setDefultMemberOnReset = null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
@@ -495,110 +556,128 @@ namespace Serein.Library
|
||||
/// </summary>
|
||||
public class LightweightFlowEnvironmentEvent : IFlowEnvironmentEvent
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public event LoadDllHandler DllLoad;
|
||||
/// <inheritdoc/>
|
||||
public event ProjectLoadedHandler ProjectLoaded;
|
||||
/// <inheritdoc/>
|
||||
public event ProjectSavingHandler ProjectSaving;
|
||||
/// <inheritdoc/>
|
||||
public event NodeConnectChangeHandler NodeConnectChanged;
|
||||
/// <inheritdoc/>
|
||||
public event CanvasCreateHandler CanvasCreated;
|
||||
/// <inheritdoc/>
|
||||
public event CanvasRemoveHandler CanvasRemoved;
|
||||
/// <inheritdoc/>
|
||||
public event NodeCreateHandler NodeCreated;
|
||||
/// <inheritdoc/>
|
||||
public event NodeRemoveHandler NodeRemoved;
|
||||
/// <inheritdoc/>
|
||||
public event NodePlaceHandler NodePlace;
|
||||
/// <inheritdoc/>
|
||||
public event NodeTakeOutHandler NodeTakeOut;
|
||||
/// <inheritdoc/>
|
||||
public event StartNodeChangeHandler StartNodeChanged;
|
||||
/// <inheritdoc/>
|
||||
public event FlowRunCompleteHandler FlowRunComplete;
|
||||
/// <inheritdoc/>
|
||||
public event MonitorObjectChangeHandler MonitorObjectChanged;
|
||||
/// <inheritdoc/>
|
||||
public event NodeInterruptStateChangeHandler NodeInterruptStateChanged;
|
||||
/// <inheritdoc/>
|
||||
public event ExpInterruptTriggerHandler InterruptTriggered;
|
||||
/// <inheritdoc/>
|
||||
public event IOCMembersChangedHandler IOCMembersChanged;
|
||||
/// <inheritdoc/>
|
||||
public event NodeLocatedHandler NodeLocated;
|
||||
/// <inheritdoc/>
|
||||
public event EnvOutHandler EnvOutput;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnDllLoad(LoadDllEventArgs eventArgs)
|
||||
{
|
||||
DllLoad?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnProjectLoaded(ProjectLoadedEventArgs eventArgs)
|
||||
{
|
||||
ProjectLoaded?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnProjectSaving(ProjectSavingEventArgs eventArgs)
|
||||
{
|
||||
ProjectSaving?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnNodeConnectChanged(NodeConnectChangeEventArgs eventArgs)
|
||||
{
|
||||
NodeConnectChanged?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnCanvasCreated(CanvasCreateEventArgs eventArgs)
|
||||
{
|
||||
CanvasCreated?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnCanvasRemoved(CanvasRemoveEventArgs eventArgs)
|
||||
{
|
||||
CanvasRemoved?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnNodeCreated(NodeCreateEventArgs eventArgs)
|
||||
{
|
||||
NodeCreated?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnNodeRemoved(NodeRemoveEventArgs eventArgs)
|
||||
{
|
||||
NodeRemoved?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnNodePlace(NodePlaceEventArgs eventArgs)
|
||||
{
|
||||
NodePlace?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnNodeTakeOut(NodeTakeOutEventArgs eventArgs)
|
||||
{
|
||||
NodeTakeOut?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnStartNodeChanged(StartNodeChangeEventArgs eventArgs)
|
||||
{
|
||||
StartNodeChanged?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnFlowRunComplete(FlowEventArgs eventArgs)
|
||||
{
|
||||
FlowRunComplete?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnMonitorObjectChanged(MonitorObjectEventArgs eventArgs)
|
||||
{
|
||||
MonitorObjectChanged?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnNodeInterruptStateChanged(NodeInterruptStateChangeEventArgs eventArgs)
|
||||
{
|
||||
NodeInterruptStateChanged?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnInterruptTriggered(InterruptTriggerEventArgs eventArgs)
|
||||
{
|
||||
InterruptTriggered?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnIOCMembersChanged(IOCMembersChangedEventArgs eventArgs)
|
||||
{
|
||||
IOCMembersChanged?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnNodeLocated(NodeLocatedEventArgs eventArgs)
|
||||
{
|
||||
NodeLocated?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnEnvOutput(InfoType type, string value)
|
||||
{
|
||||
EnvOutput?.Invoke(type, value);
|
||||
@@ -611,128 +690,131 @@ namespace Serein.Library
|
||||
/// </summary>
|
||||
public class LightweightFlowEnvironment : IFlowEnvironment
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 轻量级流程环境构造函数,接受一个流程环境事件接口。
|
||||
/// </summary>
|
||||
/// <param name="lightweightFlowEnvironmentEvent"></param>
|
||||
public LightweightFlowEnvironment(IFlowEnvironmentEvent lightweightFlowEnvironmentEvent)
|
||||
{
|
||||
this.Event = lightweightFlowEnvironmentEvent;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
public void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.Trivial)
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ISereinIOC IOC => throw new NotImplementedException();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IFlowEdit FlowEdit => throw new NotImplementedException();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IFlowControl FlowControl => throw new NotImplementedException();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IFlowEnvironmentEvent Event { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string EnvName => throw new NotImplementedException();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string ProjectFileLocation => throw new NotImplementedException();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool _IsGlobalInterrupt => throw new NotImplementedException();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsControlRemoteEnv => throw new NotImplementedException();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public InfoClass InfoClass { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
/// <inheritdoc/>
|
||||
public RunState FlowState { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IFlowEnvironment CurrentEnv => throw new NotImplementedException();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UIContextOperation UIContextOperation => throw new NotImplementedException();
|
||||
|
||||
/* public Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}*/
|
||||
|
||||
/* public Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}*/
|
||||
/// <inheritdoc/>
|
||||
public void ExitRemoteEnv()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<FlowEnvInfo> GetEnvInfoAsync()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<SereinProjectData> GetProjectInfoAsync()
|
||||
/// <inheritdoc/>
|
||||
public SereinProjectData GetProjectInfoAsync()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void LoadLibrary(string dllPath)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool LoadNativeLibraryOfRuning(string file)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void LoadProject(string filePath)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task LoadProjetAsync(string filePath)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SaveProject()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SetUIContextOperation(UIContextOperation uiContextOperation)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task StartRemoteServerAsync(int port = 7525)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void StopRemoteServer()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGetDelegateDetails(string assemblyName, string methodName, out DelegateDetails del)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGetMethodDetailsInfo(string assemblyName, string methodName, out MethodDetailsInfo mdInfo)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGetNodeModel(string nodeGuid, out IFlowNode nodeModel)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryUnloadLibrary(string assemblyFullName)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Serein.Library
|
||||
/// <summary>
|
||||
/// 每个节点有独自的MethodDetails实例
|
||||
/// </summary>
|
||||
[NodeProperty(ValuePath = NodeValuePath.Method)]
|
||||
[FlowDataProperty(ValuePath = NodeValuePath.Method)]
|
||||
public partial class MethodDetails
|
||||
{
|
||||
// private readonly IFlowEnvironment env;
|
||||
@@ -20,57 +20,51 @@ namespace Serein.Library
|
||||
/// <summary>
|
||||
/// 对应的节点
|
||||
/// </summary>
|
||||
[PropertyInfo(IsProtection = true)]
|
||||
[DataInfo(IsProtection = true)]
|
||||
private IFlowNode _nodeModel;
|
||||
|
||||
/// <summary>
|
||||
/// 对应的程序集
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private string _assemblyName;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 调用节点方法时需要的实例(多个相同的节点将拥有相同的类型)
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private Type _actingInstanceType;
|
||||
|
||||
/// <summary>
|
||||
/// 作用实例(多个相同的节点将会共享同一个实例)
|
||||
/// </summary>
|
||||
// [PropertyInfo]
|
||||
// private object _actingInstance;
|
||||
|
||||
/// <summary>
|
||||
/// 方法名称
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private string _methodName;
|
||||
|
||||
/// <summary>
|
||||
/// 节点类型
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private NodeType _methodDynamicType;
|
||||
|
||||
/// <summary>
|
||||
/// 锁名称(暂未实现)
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private string _methodLockName;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 方法别名
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private string _methodAnotherName;
|
||||
|
||||
/// <summary>
|
||||
/// 参数描述
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private ParameterDetails[] _parameterDetailss;
|
||||
|
||||
/// <summary>
|
||||
@@ -78,19 +72,19 @@ namespace Serein.Library
|
||||
/// <para>-1表示不存在</para>
|
||||
/// <para>0表示第一个参数是可选参数</para>
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private int _paramsArgIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// 是否为异步方法(如果为异步方法,则返回值类型为Task或Task<T>)
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private bool _isAsync = false;
|
||||
|
||||
/// <summary>
|
||||
/// 出参类型
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private Type _returnType;
|
||||
}
|
||||
|
||||
@@ -133,7 +127,11 @@ namespace Serein.Library
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 新增可变参数
|
||||
/// </summary>
|
||||
/// <param name="parameterDetails"></param>
|
||||
/// <returns></returns>
|
||||
public bool AddParamsArg(ParameterDetails parameterDetails)
|
||||
{
|
||||
if (ParamsArgIndex < 0) // 方法是否包含可变参数
|
||||
@@ -313,6 +311,10 @@ namespace Serein.Library
|
||||
return md;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将方法信息转换为字符串,方便调试和查看
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
if (string.IsNullOrEmpty(this.MethodName))
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Serein.Library
|
||||
/// <summary>
|
||||
/// 节点调试设置,用于中断节点的运行
|
||||
/// </summary>
|
||||
[NodeProperty(ValuePath = NodeValuePath.DebugSetting)]
|
||||
[FlowDataProperty(ValuePath = NodeValuePath.DebugSetting)]
|
||||
public partial class NodeDebugSetting
|
||||
{
|
||||
/// <summary>
|
||||
@@ -24,25 +24,25 @@ namespace Serein.Library
|
||||
/// <summary>
|
||||
/// 是否保护参数
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true)]
|
||||
[DataInfo(IsNotification = true)]
|
||||
private bool _isProtectionParameter = false;
|
||||
|
||||
/// <summary>
|
||||
/// 对应的节点
|
||||
/// </summary>
|
||||
[PropertyInfo(IsProtection = true)]
|
||||
[DataInfo(IsProtection = true)]
|
||||
private IFlowNode _nodeModel;
|
||||
|
||||
/// <summary>
|
||||
/// 是否使能
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true)]
|
||||
[DataInfo(IsNotification = true)]
|
||||
private bool _isEnable = true;
|
||||
|
||||
/// <summary>
|
||||
/// 是否中断节点。
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true)]
|
||||
[DataInfo(IsNotification = true)]
|
||||
private bool _isInterrupt = false;
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,11 @@ namespace Serein.Library
|
||||
/// </summary>
|
||||
public Type ViewModelType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 节点类型信息字符串表示
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"$[{NodeType}]类型信息 : ModelType->{ModelType};ControlType->{ControlType};ViewModelType->{ViewModelType}";
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Serein.Library
|
||||
/// <summary>
|
||||
/// 节点入参参数详情
|
||||
/// </summary>
|
||||
[NodeProperty(ValuePath = NodeValuePath.Parameter)]
|
||||
[FlowDataProperty(ValuePath = NodeValuePath.Parameter)]
|
||||
public partial class ParameterDetails
|
||||
{
|
||||
// private readonly IFlowEnvironment env;
|
||||
@@ -22,13 +22,13 @@ namespace Serein.Library
|
||||
/// <summary>
|
||||
/// 所在的节点
|
||||
/// </summary>
|
||||
[PropertyInfo(IsProtection = true)]
|
||||
[DataInfo(IsProtection = true)]
|
||||
private IFlowNode _nodeModel;
|
||||
|
||||
/// <summary>
|
||||
/// 参数索引
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private int _index;
|
||||
|
||||
/// <summary>
|
||||
@@ -36,7 +36,7 @@ namespace Serein.Library
|
||||
/// <para>如果为 true ,则使用输入的文本值作为入参数据。</para>
|
||||
/// <para>如果为 false ,则在当前流程上下文中,根据 ArgDataSourceNodeGuid 查找到对应节点,并根据 ArgDataSourceNodeGuid 判断如何获取其返回的数据,以此作为入参数据。</para>
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true, IsVerify = true)]
|
||||
[DataInfo(IsNotification = true, IsVerify = true)]
|
||||
private bool _isExplicitData ;
|
||||
|
||||
///// <summary>
|
||||
@@ -49,7 +49,7 @@ namespace Serein.Library
|
||||
/// 方法入参若无相关转换器特性标注,则无需关注该变量。该变量用于需要用到枚举BinValue转换器时,指示相应的入参变量需要转为的类型。
|
||||
/// </summary>
|
||||
[Obsolete("转换器特性将在下一个大版本中移除")]
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private Type _explicitType ;
|
||||
|
||||
/// <summary>
|
||||
@@ -58,56 +58,56 @@ namespace Serein.Library
|
||||
/// <para>Bool : 布尔类型</para>
|
||||
/// <para>Value :除以上类型之外的任意参数</para>
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private ParameterValueInputType _inputType ;
|
||||
|
||||
/// <summary>
|
||||
/// 入参数据来源。默认使用上一节点作为入参数据。
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true)]
|
||||
[DataInfo(IsNotification = true)]
|
||||
private ConnectionArgSourceType _argDataSourceType = ConnectionArgSourceType.GetPreviousNodeData;
|
||||
|
||||
/// <summary>
|
||||
/// 当 ArgDataSourceType 不为 GetPreviousNodeData 时(从运行时上一节点获取数据)。
|
||||
/// 则通过当前上下文,获取该Guid对应的数据作为预处理的入参参数。
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private string _argDataSourceNodeGuid;
|
||||
|
||||
/// <summary>
|
||||
/// 方法入参需要的类型。
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private Type _dataType ;
|
||||
|
||||
/// <summary>
|
||||
/// 方法入参参数名称
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true)]
|
||||
[DataInfo(IsNotification = true)]
|
||||
private string _name ;
|
||||
|
||||
/// <summary>
|
||||
/// 入参注释
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private string _description;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义的方法入参数据
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true)] // IsPrint = true
|
||||
[DataInfo(IsNotification = true)] // IsPrint = true
|
||||
private string _dataValue;
|
||||
|
||||
/// <summary>
|
||||
/// 只有当 InputType 为 Select 时,才会需要该成员。
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true)]
|
||||
[DataInfo(IsNotification = true)]
|
||||
private string[] _items ;
|
||||
|
||||
/// <summary>
|
||||
/// 指示该属性是可变参数的其中一员(可变参数为数组类型)
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private bool _isParams;
|
||||
}
|
||||
|
||||
@@ -134,6 +134,11 @@ namespace Serein.Library
|
||||
this.NodeModel = nodeModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过参数数据加载实体,用于加载项目文件、远程连接的场景
|
||||
/// </summary>
|
||||
/// <param name="pdInfo"></param>
|
||||
/// <param name="argIndex"></param>
|
||||
public ParameterDetails(ParameterData pdInfo, int argIndex)
|
||||
{
|
||||
this.Index = argIndex;
|
||||
@@ -163,6 +168,7 @@ namespace Serein.Library
|
||||
IsParams = info.IsParams;
|
||||
}
|
||||
|
||||
|
||||
partial void BeforeTheIsExplicitData(ref bool __isAllow, bool newValue)
|
||||
{
|
||||
if(DataType == typeof(IFlowContext))
|
||||
@@ -214,6 +220,12 @@ namespace Serein.Library
|
||||
return pd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转为方法入参数据
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public async Task<object> ToMethodArgData(IFlowContext context)
|
||||
{
|
||||
// 1. 从缓存获取
|
||||
@@ -310,177 +322,181 @@ namespace Serein.Library
|
||||
|
||||
|
||||
|
||||
/* /// <summary>
|
||||
/// 转为方法入参数据
|
||||
/* /// <summary>
|
||||
/// 转为方法入参数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<object> ToMethodArgData2(IFlowContext context)
|
||||
{
|
||||
|
||||
var nodeModel = NodeModel;
|
||||
var env = nodeModel.Env;
|
||||
|
||||
#region 流程运行上下文预设的参数
|
||||
if (context.TryGetParamsTempData(NodeModel.Guid, Index, out var data))
|
||||
{
|
||||
return data;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 显然的流程基本类型
|
||||
// 返回运行环境
|
||||
if (typeof(IFlowEnvironment).IsAssignableFrom(DataType))
|
||||
{
|
||||
return env;
|
||||
}
|
||||
// 返回流程上下文
|
||||
if (typeof(IFlowContext).IsAssignableFrom(DataType))
|
||||
{
|
||||
return context;
|
||||
}
|
||||
// 返回流程上下文
|
||||
if (typeof(IFlowNode).IsAssignableFrom(DataType))
|
||||
{
|
||||
return NodeModel;
|
||||
}
|
||||
// 显式设置的参数
|
||||
if (IsExplicitData && !DataValue.StartsWith("@", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return DataValue.ToConvertValueType(DataType); // 并非表达式,同时是显式设置的参数
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*//*#region “枚举-类型”转换器
|
||||
if (ExplicitType is not null && ExplicitType.IsEnum && DataType != ExplicitType)
|
||||
{
|
||||
var resultEnum = Enum.Parse(ExplicitType, DataValue);
|
||||
// 获取绑定的类型
|
||||
var type = EnumHelper.GetBoundValue(ExplicitType, resultEnum, attr => attr.Value);
|
||||
if (type is Type enumBindType && !(enumBindType is null))
|
||||
{
|
||||
var value = nodeModel.Env.IOC.CreateObject(enumBindType);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
#endregion*//*
|
||||
|
||||
// 需要获取预入参数据
|
||||
object inputParameter;
|
||||
#region (默认的)从运行时上游节点获取其返回值
|
||||
|
||||
if (ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData)
|
||||
{
|
||||
var previousNode = context.GetPreviousNode(nodeModel.Guid);
|
||||
if (previousNode is null)
|
||||
{
|
||||
inputParameter = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var flowData = context.GetFlowData(previousNode);
|
||||
inputParameter = flowData.Value; // 当前传递的数据
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
if(!env.TryGetNodeModel(ArgDataSourceNodeGuid, out var argSourceNodeModel))
|
||||
{
|
||||
throw new Exception($"[arg{Index}][{Name}][{DataType}]需要节点[{ArgDataSourceNodeGuid}]的参数,但节点不存在");
|
||||
}
|
||||
|
||||
// 如果是公开的节点,需要判断上下文调用中是否存在流程接口节点
|
||||
if (argSourceNodeModel.IsPublic)
|
||||
{
|
||||
var pnGuid = context.GetPreviousNode(NodeModel.Guid);
|
||||
var pn = env.TryGetNodeModel(pnGuid, out var tmpNode) ? tmpNode : null;
|
||||
if (pn.ControlType == NodeControlType.FlowCall)
|
||||
{
|
||||
argSourceNodeModel = pn;
|
||||
}
|
||||
}
|
||||
|
||||
if (ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
||||
{
|
||||
var flowData = context.GetFlowData(argSourceNodeModel.Guid);
|
||||
if(flowData is null)
|
||||
{
|
||||
inputParameter = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
inputParameter = flowData.Value;
|
||||
}
|
||||
}
|
||||
else if (ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
||||
{
|
||||
// 立刻调用对应节点获取数据。
|
||||
var cts = new CancellationTokenSource();
|
||||
var result = await argSourceNodeModel.ExecutingAsync(context, cts.Token);
|
||||
cts?.Cancel();
|
||||
cts?.Dispose();
|
||||
inputParameter = result.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("节点执行方法获取入参参数时,ConnectionArgSourceType枚举是意外的枚举值");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region 判断是否执行表达式
|
||||
if (IsExplicitData)
|
||||
{
|
||||
// @Get 表达式 (从上一节点获取对象)
|
||||
if (DataValue.StartsWith("@get", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
inputParameter = SerinExpressionEvaluator.Evaluate(DataValue, inputParameter, out _);
|
||||
}
|
||||
|
||||
// @DTC 表达式 (Data type conversion)
|
||||
else if (DataValue.StartsWith("@dtc", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
inputParameter = SerinExpressionEvaluator.Evaluate(DataValue, inputParameter, out _);
|
||||
}
|
||||
|
||||
// @Data 表达式 (获取全局数据)
|
||||
else if (DataValue.StartsWith("@data", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
inputParameter = SerinExpressionEvaluator.Evaluate(DataValue, inputParameter, out _);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// 对引用类型检查 null
|
||||
if (!DataType.IsValueType && inputParameter is null)
|
||||
{
|
||||
throw new Exception($"[arg{Index}][{Name}][{DataType}]参数不能为null");
|
||||
}
|
||||
if (DataType == typeof(string)) // 转为字符串
|
||||
{
|
||||
return inputParameter.ToString();
|
||||
}
|
||||
var inputParameterType = inputParameter.GetType();
|
||||
if (DataType.IsSubclassOf(inputParameterType)) // 入参类型 是 预入参数据类型 的 子类/实现类
|
||||
{
|
||||
// 方法入参中,父类不能隐式转为子类,这里需要进行强制转换
|
||||
return ObjectConvertHelper.ConvertParentToChild(inputParameter, DataType);
|
||||
}
|
||||
if (DataType.IsAssignableFrom(inputParameterType)) // 入参类型 是 预入参数据类型 的 父类/接口
|
||||
{
|
||||
return inputParameter;
|
||||
}
|
||||
|
||||
throw new Exception($"[arg{Index}][{Name}][{DataType}]入参类型不符合,当前预入参类型为{inputParameterType}");
|
||||
}
|
||||
*/
|
||||
/// <summary>
|
||||
/// 转为字符串描述
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<object> ToMethodArgData2(IFlowContext context)
|
||||
{
|
||||
|
||||
var nodeModel = NodeModel;
|
||||
var env = nodeModel.Env;
|
||||
|
||||
#region 流程运行上下文预设的参数
|
||||
if (context.TryGetParamsTempData(NodeModel.Guid, Index, out var data))
|
||||
{
|
||||
return data;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 显然的流程基本类型
|
||||
// 返回运行环境
|
||||
if (typeof(IFlowEnvironment).IsAssignableFrom(DataType))
|
||||
{
|
||||
return env;
|
||||
}
|
||||
// 返回流程上下文
|
||||
if (typeof(IFlowContext).IsAssignableFrom(DataType))
|
||||
{
|
||||
return context;
|
||||
}
|
||||
// 返回流程上下文
|
||||
if (typeof(IFlowNode).IsAssignableFrom(DataType))
|
||||
{
|
||||
return NodeModel;
|
||||
}
|
||||
// 显式设置的参数
|
||||
if (IsExplicitData && !DataValue.StartsWith("@", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return DataValue.ToConvertValueType(DataType); // 并非表达式,同时是显式设置的参数
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*//*#region “枚举-类型”转换器
|
||||
if (ExplicitType is not null && ExplicitType.IsEnum && DataType != ExplicitType)
|
||||
{
|
||||
var resultEnum = Enum.Parse(ExplicitType, DataValue);
|
||||
// 获取绑定的类型
|
||||
var type = EnumHelper.GetBoundValue(ExplicitType, resultEnum, attr => attr.Value);
|
||||
if (type is Type enumBindType && !(enumBindType is null))
|
||||
{
|
||||
var value = nodeModel.Env.IOC.CreateObject(enumBindType);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
#endregion*//*
|
||||
|
||||
// 需要获取预入参数据
|
||||
object inputParameter;
|
||||
#region (默认的)从运行时上游节点获取其返回值
|
||||
|
||||
if (ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData)
|
||||
{
|
||||
var previousNode = context.GetPreviousNode(nodeModel.Guid);
|
||||
if (previousNode is null)
|
||||
{
|
||||
inputParameter = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var flowData = context.GetFlowData(previousNode);
|
||||
inputParameter = flowData.Value; // 当前传递的数据
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
if(!env.TryGetNodeModel(ArgDataSourceNodeGuid, out var argSourceNodeModel))
|
||||
{
|
||||
throw new Exception($"[arg{Index}][{Name}][{DataType}]需要节点[{ArgDataSourceNodeGuid}]的参数,但节点不存在");
|
||||
}
|
||||
|
||||
// 如果是公开的节点,需要判断上下文调用中是否存在流程接口节点
|
||||
if (argSourceNodeModel.IsPublic)
|
||||
{
|
||||
var pnGuid = context.GetPreviousNode(NodeModel.Guid);
|
||||
var pn = env.TryGetNodeModel(pnGuid, out var tmpNode) ? tmpNode : null;
|
||||
if (pn.ControlType == NodeControlType.FlowCall)
|
||||
{
|
||||
argSourceNodeModel = pn;
|
||||
}
|
||||
}
|
||||
|
||||
if (ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
||||
{
|
||||
var flowData = context.GetFlowData(argSourceNodeModel.Guid);
|
||||
if(flowData is null)
|
||||
{
|
||||
inputParameter = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
inputParameter = flowData.Value;
|
||||
}
|
||||
}
|
||||
else if (ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
||||
{
|
||||
// 立刻调用对应节点获取数据。
|
||||
var cts = new CancellationTokenSource();
|
||||
var result = await argSourceNodeModel.ExecutingAsync(context, cts.Token);
|
||||
cts?.Cancel();
|
||||
cts?.Dispose();
|
||||
inputParameter = result.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("节点执行方法获取入参参数时,ConnectionArgSourceType枚举是意外的枚举值");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region 判断是否执行表达式
|
||||
if (IsExplicitData)
|
||||
{
|
||||
// @Get 表达式 (从上一节点获取对象)
|
||||
if (DataValue.StartsWith("@get", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
inputParameter = SerinExpressionEvaluator.Evaluate(DataValue, inputParameter, out _);
|
||||
}
|
||||
|
||||
// @DTC 表达式 (Data type conversion)
|
||||
else if (DataValue.StartsWith("@dtc", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
inputParameter = SerinExpressionEvaluator.Evaluate(DataValue, inputParameter, out _);
|
||||
}
|
||||
|
||||
// @Data 表达式 (获取全局数据)
|
||||
else if (DataValue.StartsWith("@data", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
inputParameter = SerinExpressionEvaluator.Evaluate(DataValue, inputParameter, out _);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// 对引用类型检查 null
|
||||
if (!DataType.IsValueType && inputParameter is null)
|
||||
{
|
||||
throw new Exception($"[arg{Index}][{Name}][{DataType}]参数不能为null");
|
||||
}
|
||||
if (DataType == typeof(string)) // 转为字符串
|
||||
{
|
||||
return inputParameter.ToString();
|
||||
}
|
||||
var inputParameterType = inputParameter.GetType();
|
||||
if (DataType.IsSubclassOf(inputParameterType)) // 入参类型 是 预入参数据类型 的 子类/实现类
|
||||
{
|
||||
// 方法入参中,父类不能隐式转为子类,这里需要进行强制转换
|
||||
return ObjectConvertHelper.ConvertParentToChild(inputParameter, DataType);
|
||||
}
|
||||
if (DataType.IsAssignableFrom(inputParameterType)) // 入参类型 是 预入参数据类型 的 父类/接口
|
||||
{
|
||||
return inputParameter;
|
||||
}
|
||||
|
||||
throw new Exception($"[arg{Index}][{Name}][{DataType}]入参类型不符合,当前预入参类型为{inputParameterType}");
|
||||
}
|
||||
*/
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[{this.Index}] {(string.IsNullOrWhiteSpace(this.Description) ? string.Empty : $"({this.Description})")}{this.Name} : {this.DataType?.FullName}";
|
||||
|
||||
@@ -270,7 +270,7 @@ namespace Serein.Library
|
||||
/// <summary>
|
||||
/// 节点于画布中的位置(通用类)
|
||||
/// </summary>
|
||||
[NodeProperty]
|
||||
[FlowDataProperty]
|
||||
public partial class PositionOfUI
|
||||
{
|
||||
/// <summary>
|
||||
@@ -285,13 +285,13 @@ namespace Serein.Library
|
||||
/// <summary>
|
||||
/// 指示控件在画布的横向向方向上的位置
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private double _x = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 指示控件在画布的纵向方向上的位置
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
[DataInfo]
|
||||
private double _y = 0;
|
||||
}
|
||||
|
||||
|
||||
8
Library/Properties/launchSettings.json
Normal file
8
Library/Properties/launchSettings.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Serein.Library": {
|
||||
"commandName": "Project",
|
||||
"remoteDebugEnabled": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,35 +8,83 @@ namespace Serein.Library
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 脚本代码中常用的函数
|
||||
/// </summary>
|
||||
public static class ScriptBaseFunc
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取当前时间
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static DateTime now() => DateTime.Now;
|
||||
|
||||
#region 常用的类型转换
|
||||
/// <summary>
|
||||
/// 将值转换为bool类型
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static bool @bool(object value)
|
||||
{
|
||||
return ConvertHelper.ValueParse<bool>(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将值转换为字节类型
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static byte @byte(object value)
|
||||
{
|
||||
return ConvertHelper.ValueParse<byte>(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将值转换为短整型
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static decimal @decimal(object value)
|
||||
{
|
||||
return ConvertHelper.ValueParse<decimal>(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将值转换为浮点型
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static float @float(object value)
|
||||
{
|
||||
return ConvertHelper.ValueParse<float>(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将值转换为双精度浮点型
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static double @double(object value)
|
||||
{
|
||||
return ConvertHelper.ValueParse<double>(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将值转换为整数类型
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static int @int(object value)
|
||||
{
|
||||
return ConvertHelper.ValueParse<int>(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将值转换为长整型
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static int @long(object value)
|
||||
{
|
||||
return ConvertHelper.ValueParse<int>(value);
|
||||
@@ -44,6 +92,12 @@ namespace Serein.Library
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 获取集合或数组的长度
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public static int len(object target)
|
||||
{
|
||||
// 获取数组或集合对象
|
||||
@@ -70,28 +124,50 @@ namespace Serein.Library
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 将对象转换为字符串
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static string str(object obj)
|
||||
{
|
||||
return obj?.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取全局数据
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public static object global(string name)
|
||||
{
|
||||
return SereinEnv.GetFlowGlobalData(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象的类型
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static Type type(object type)
|
||||
{
|
||||
return type.GetType();
|
||||
}
|
||||
/// <summary>
|
||||
/// 记录日志信息
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
|
||||
public static void log(object value)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.INFO, value?.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 等待一段时间
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task sleep(object value)
|
||||
{
|
||||
if (value is int @int)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<Title>SereinFow</Title>
|
||||
<Version>1.2.2</Version>
|
||||
<Version>1.2.3</Version>
|
||||
<Description>动态节点流、可视化编辑的基本依赖,支持导入C# DLL生成自定义节点,提供二次开发支持,适合用于可视化编程和流程设计</Description>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>https://github.com/fhhyyp/serein-flow</RepositoryUrl>
|
||||
@@ -61,18 +61,13 @@
|
||||
<Compile Remove="FlowNode\NodeModelBaseFunc.cs" />
|
||||
<Compile Remove="FlowNode\ScriptFlowApi.cs" />
|
||||
<Compile Remove="Utils\NativeDllHelper.cs" />
|
||||
<Compile Remove="Utils\RemoteMsgUtil.cs" />
|
||||
<Compile Remove="Utils\RemoteMsgUtil.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
|
||||
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.0" />
|
||||
<PackageReference Include="System.IO.Ports" Version="9.0.7" />
|
||||
<PackageReference Include="System.Reactive" Version="6.0.1" />
|
||||
<PackageReference Include="System.Threading.Channels" Version="8.0.0" />
|
||||
<PackageReference Include="System.ValueTuple" Version="4.3.0" />
|
||||
<!--<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />-->
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -87,6 +82,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!--<ProjectReference Include="..\Serein.Library.MyGenerator\Serein.Library.NodeGenerator.csproj " OutputItemType="Analyzer" />-->
|
||||
<!-- ReferenceOutputAssembly="false" -->
|
||||
<ProjectReference Include="..\Serein.Library.MyGenerator\Serein.Library.NodeGenerator.csproj " OutputItemType="Analyzer" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -6,6 +6,9 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// 数组操作的工具类
|
||||
/// </summary>
|
||||
public class ArrayHelper
|
||||
{
|
||||
|
||||
|
||||
@@ -270,6 +270,14 @@ namespace Serein.Library.Utils
|
||||
|
||||
return (T)result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将字符串转换为指定类型的值对象。
|
||||
/// </summary>
|
||||
/// <param name="valueStr"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public static object ToValueData(this string valueStr, Type type)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(valueStr))
|
||||
|
||||
@@ -41,21 +41,40 @@ namespace Serein.Library.Utils
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析字典属性并创建对象实例
|
||||
/// </summary>
|
||||
/// <param name="properties"></param>
|
||||
/// <param name="typeName"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
public static object Resolve(IDictionary<string, object> properties, string typeName)
|
||||
{
|
||||
var obj = CreateObjectWithProperties(properties, typeName);
|
||||
//SetPropertyValues(obj, properties);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试解析字典属性并创建对象实例
|
||||
/// </summary>
|
||||
/// <param name="properties"></param>
|
||||
/// <param name="typeName"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <returns></returns>
|
||||
public static bool TryResolve(IDictionary<string, object> properties, string typeName, out object result)
|
||||
{
|
||||
result = CreateObjectWithProperties(properties, typeName);
|
||||
bool success = SetPropertyValuesWithValidation(result, properties);
|
||||
return success;
|
||||
// 打印赋值结果
|
||||
|
||||
}
|
||||
// 递归方法:打印对象属性及类型
|
||||
|
||||
/// <summary>
|
||||
/// 打印对象属性及类型
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="indent"></param>
|
||||
public static void PrintObjectProperties(object obj, string indent = "")
|
||||
{
|
||||
var objType = obj.GetType();
|
||||
@@ -327,7 +346,12 @@ namespace Serein.Library.Utils
|
||||
}
|
||||
#region 动态创建对象并赋值
|
||||
|
||||
// 方法 1: 创建动态类型及其对象实例
|
||||
/// <summary>
|
||||
/// 创建动态类型及其对象实例
|
||||
/// </summary>
|
||||
/// <param name="properties"></param>
|
||||
/// <param name="typeName"></param>
|
||||
/// <returns></returns>
|
||||
public static object CreateObjectWithProperties(IDictionary<string, object> properties, string typeName)
|
||||
{
|
||||
// 如果类型已经缓存,直接返回缓存的类型
|
||||
@@ -410,8 +434,12 @@ namespace Serein.Library.Utils
|
||||
return Activator.CreateInstance(dynamicType);
|
||||
}
|
||||
|
||||
// 方法 2: 递归设置对象的属性值
|
||||
public static void SetPropertyValues(object obj, Dictionary<string, object> properties)
|
||||
/// <summary>
|
||||
/// 递归设置对象的属性值
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="properties"></param>
|
||||
private static void SetPropertyValues(object obj, Dictionary<string, object> properties)
|
||||
{
|
||||
var objType = obj.GetType();
|
||||
|
||||
@@ -439,8 +467,13 @@ namespace Serein.Library.Utils
|
||||
}
|
||||
}
|
||||
}
|
||||
// 方法 2: 递归设置对象的属性值(带验证)
|
||||
|
||||
/// <summary>
|
||||
/// 递归设置对象的属性值(带验证)
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="properties"></param>
|
||||
/// <returns></returns>
|
||||
public static bool SetPropertyValuesWithValidation(object obj, IDictionary<string, object> properties)
|
||||
{
|
||||
var objType = obj.GetType();
|
||||
|
||||
@@ -9,12 +9,15 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Emit创建委托工具类
|
||||
/// </summary>
|
||||
public class EmitHelper
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 动态方法信息
|
||||
/// </summary>
|
||||
public class EmitMethodInfo
|
||||
{
|
||||
/// <summary>
|
||||
@@ -39,6 +42,9 @@ namespace Serein.Library.Utils
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 方法类型枚举
|
||||
/// </summary>
|
||||
public enum EmitMethodType
|
||||
{
|
||||
/// <summary>
|
||||
@@ -55,12 +61,19 @@ namespace Serein.Library.Utils
|
||||
TaskHasResult,
|
||||
}
|
||||
|
||||
public static bool IsGenericTask(Type returnType, out Type taskResult)
|
||||
/// <summary>
|
||||
/// 判断一个类型是否为泛型 Task<T> 或 Task,并返回泛型参数类型(如果有的话)
|
||||
/// </summary>
|
||||
/// <param name="returnType"></param>
|
||||
/// <param name="taskResult"></param>
|
||||
/// <returns></returns>
|
||||
#nullable enable
|
||||
public static bool IsGenericTask(Type returnType, out Type? taskResult)
|
||||
{
|
||||
// 判断是否为 Task 类型或泛型 Task<T>
|
||||
if (returnType == typeof(Task))
|
||||
{
|
||||
taskResult = null;
|
||||
taskResult = typeof(void);
|
||||
return true;
|
||||
}
|
||||
else if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
|
||||
@@ -78,7 +91,6 @@ namespace Serein.Library.Utils
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 根据方法信息创建动态调用的委托,返回方法类型,以及传出一个委托
|
||||
/// </summary>
|
||||
@@ -87,6 +99,10 @@ namespace Serein.Library.Utils
|
||||
/// <returns></returns>
|
||||
public static EmitMethodInfo CreateDynamicMethod(MethodInfo methodInfo,out Delegate @delegate)
|
||||
{
|
||||
if (methodInfo.DeclaringType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(methodInfo.DeclaringType));
|
||||
}
|
||||
EmitMethodInfo emitMethodInfo = new EmitMethodInfo();
|
||||
bool IsTask = IsGenericTask(methodInfo.ReturnType, out var taskGenericsType);
|
||||
bool IsTaskGenerics = taskGenericsType != null;
|
||||
@@ -219,6 +235,10 @@ namespace Serein.Library.Utils
|
||||
{
|
||||
if (fieldInfo == null)
|
||||
throw new ArgumentNullException(nameof(fieldInfo));
|
||||
|
||||
if (fieldInfo.DeclaringType == null)
|
||||
throw new ArgumentNullException(nameof(fieldInfo.DeclaringType));
|
||||
|
||||
|
||||
var method = new DynamicMethod(
|
||||
fieldInfo.Name + "_Get",
|
||||
@@ -257,6 +277,8 @@ namespace Serein.Library.Utils
|
||||
{
|
||||
if (fieldInfo == null)
|
||||
throw new ArgumentNullException(nameof(fieldInfo));
|
||||
if (fieldInfo.DeclaringType == null)
|
||||
throw new ArgumentNullException(nameof(fieldInfo.DeclaringType));
|
||||
if (fieldInfo.IsInitOnly)
|
||||
throw new InvalidOperationException($"字段 {fieldInfo.Name} 是只读字段,无法设置值。");
|
||||
|
||||
@@ -299,6 +321,8 @@ namespace Serein.Library.Utils
|
||||
{
|
||||
if (propertyInfo == null)
|
||||
throw new ArgumentNullException(nameof(propertyInfo));
|
||||
if (propertyInfo.DeclaringType == null)
|
||||
throw new ArgumentNullException(nameof(propertyInfo.DeclaringType));
|
||||
var getMethod = propertyInfo.GetGetMethod(true);
|
||||
if (getMethod == null)
|
||||
throw new InvalidOperationException($"属性 {propertyInfo.Name} 没有可用的 Getter。");
|
||||
@@ -339,6 +363,9 @@ namespace Serein.Library.Utils
|
||||
{
|
||||
if (propertyInfo == null)
|
||||
throw new ArgumentNullException(nameof(propertyInfo));
|
||||
if (propertyInfo.DeclaringType == null)
|
||||
throw new ArgumentNullException(nameof(propertyInfo.DeclaringType));
|
||||
|
||||
var setMethod = propertyInfo.GetSetMethod(true);
|
||||
if (setMethod == null)
|
||||
throw new InvalidOperationException($"属性 {propertyInfo.Name} 没有可用的 Setter。");
|
||||
|
||||
@@ -59,6 +59,13 @@ namespace Serein.Library.Utils
|
||||
return attribute != null ? (TResult)valueSelector(attribute) : default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从枚举值的 BindValueAttribute 特性中 获取绑定的参数(用于绑定了某些内容的枚举值)
|
||||
/// </summary>
|
||||
/// <param name="enumType"></param>
|
||||
/// <param name="enumValue"></param>
|
||||
/// <param name="valueSelector"></param>
|
||||
/// <returns></returns>
|
||||
public static object GetBoundValue(Type enumType,object enumValue, Func<BindValueAttribute, object> valueSelector)
|
||||
{
|
||||
var fieldInfo = enumType.GetField(enumValue.ToString());
|
||||
|
||||
@@ -146,7 +146,7 @@ namespace Serein.Library.Utils
|
||||
var parameter = Expression.Parameter(typeof(object), "instance");
|
||||
var methodCall = Expression.Call(Expression.Convert(parameter, type), methodInfo);
|
||||
|
||||
if (IsGenericTask(methodInfo.ReturnType, out var taskResult))
|
||||
if (EmitHelper.IsGenericTask(methodInfo.ReturnType, out var taskResult))
|
||||
{
|
||||
if (taskResult is null)
|
||||
{
|
||||
@@ -278,7 +278,7 @@ namespace Serein.Library.Utils
|
||||
convertedArgs
|
||||
);
|
||||
|
||||
if (IsGenericTask(methodInfo.ReturnType, out var taskResult))
|
||||
if (EmitHelper.IsGenericTask(methodInfo.ReturnType, out var taskResult))
|
||||
{
|
||||
if (taskResult is null)
|
||||
{
|
||||
@@ -305,7 +305,7 @@ namespace Serein.Library.Utils
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 表达式树构建无参数,有返回值(Task<object>)的方法(触发器)
|
||||
/// 表达式树构建无参数,有返回值(Task<object>)的方法(触发器)
|
||||
/// </summary>
|
||||
public static Delegate MethodCallerAsync(Type type, MethodInfo methodInfo)
|
||||
{
|
||||
@@ -314,7 +314,7 @@ namespace Serein.Library.Utils
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表达式树构建无参数,有返回值(Task<object>)的方法(触发器)
|
||||
/// 表达式树构建无参数,有返回值(Task<object>)的方法(触发器)
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="methodInfo"></param>
|
||||
@@ -332,7 +332,7 @@ namespace Serein.Library.Utils
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 表达式树构建多个参数,有返回值(Task-object)的方法(触发器)
|
||||
/// 表达式树构建多个参数,有返回值(Task<object>)的方法(触发器)
|
||||
/// </summary>
|
||||
public static Delegate MethodCallerAsync(Type type, MethodInfo method, params Type[] parameterTypes)
|
||||
{
|
||||
@@ -342,7 +342,7 @@ namespace Serein.Library.Utils
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表达式树构建多个参数,有返回值(Task<object>)的方法(触发器)
|
||||
/// 表达式树构建多个参数,有返回值(Task<object>)的方法(触发器)
|
||||
/// </summary>
|
||||
private static Delegate CreateMethodCallerDelegateAsync(Type type, MethodInfo methodInfo, Type[] parameterTypes)
|
||||
{
|
||||
@@ -384,31 +384,12 @@ namespace Serein.Library.Utils
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static bool IsGenericTask(Type returnType, out Type taskResult)
|
||||
{
|
||||
// 判断是否为 Task 类型或泛型 Task<T>
|
||||
if (returnType == typeof(Task))
|
||||
{
|
||||
taskResult = null;
|
||||
return true;
|
||||
}
|
||||
else if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
|
||||
{
|
||||
// 获取泛型参数类型
|
||||
Type genericArgument = returnType.GetGenericArguments()[0];
|
||||
taskResult = genericArgument;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
taskResult = null;
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// / 自动创建一个委托,根据方法信息和类型
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="methodInfo"></param>
|
||||
/// <returns></returns>
|
||||
public static Delegate AutoCreate(Type type, MethodInfo methodInfo)
|
||||
{
|
||||
Type returnType = methodInfo.ReturnType;
|
||||
|
||||
@@ -9,6 +9,10 @@ using System.Threading.Tasks;
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 基于 Channel 的触发器实现
|
||||
/// </summary>
|
||||
/// <typeparam name="TSignal"></typeparam>
|
||||
public class ChannelFlowTrigger<TSignal> : IFlowTrigger<TSignal>
|
||||
{
|
||||
// 使用并发字典管理每个枚举信号对应的 Channel
|
||||
@@ -24,6 +28,13 @@ namespace Serein.Library.Utils
|
||||
return _channels.GetOrAdd(signal, _ => Channel.CreateUnbounded<TriggerResult<object>>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 等待信号触发并指定超时时间
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
/// <param name="signal"></param>
|
||||
/// <param name="outTime"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<TriggerResult<TResult>> WaitTriggerWithTimeoutAsync<TResult>(TSignal signal, TimeSpan outTime)
|
||||
{
|
||||
var channel = GetOrCreateChannel(signal);
|
||||
@@ -54,6 +65,12 @@ namespace Serein.Library.Utils
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 等待信号触发
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
/// <param name="signal"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<TriggerResult<TResult>> WaitTriggerAsync<TResult>(TSignal signal)
|
||||
{
|
||||
var channel = GetOrCreateChannel(signal);
|
||||
@@ -76,6 +93,13 @@ namespace Serein.Library.Utils
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 调用触发器
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
/// <param name="signal"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> InvokeTriggerAsync<TResult>(TSignal signal, TResult value)
|
||||
{
|
||||
if (_channels.TryGetValue(signal, out var channel))
|
||||
@@ -92,6 +116,9 @@ namespace Serein.Library.Utils
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消所有触发器
|
||||
/// </summary>
|
||||
public void CancelAllTrigger()
|
||||
{
|
||||
foreach (var channel in _channels.Values)
|
||||
|
||||
@@ -141,13 +141,30 @@ namespace Serein.Library.Utils
|
||||
{
|
||||
private readonly Action<T> _onNext;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数,接受一个 Action 作为回调
|
||||
/// </summary>
|
||||
/// <param name="onNext"></param>
|
||||
public Observer(Action<T> onNext)
|
||||
{
|
||||
_onNext = onNext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通知订阅者已完成或发生错误
|
||||
/// </summary>
|
||||
public void OnCompleted() { }
|
||||
|
||||
/// <summary>
|
||||
/// 通知订阅者发生错误
|
||||
/// </summary>
|
||||
/// <param name="error"></param>
|
||||
public void OnError(Exception error) { }
|
||||
|
||||
/// <summary>
|
||||
/// 通知订阅者有新数据到来
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void OnNext(T value)
|
||||
{
|
||||
_onNext?.Invoke(value);
|
||||
|
||||
@@ -7,9 +7,20 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// 触发器结果类,用于存储触发器的类型和返回值。
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
public class TriggerResult<TResult>
|
||||
{
|
||||
/// <summary>
|
||||
/// 触发类型
|
||||
/// </summary>
|
||||
public TriggerDescription Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 触发结果值
|
||||
/// </summary>
|
||||
public TResult Value { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,28 +23,57 @@ namespace Serein.Library.Utils
|
||||
JsonHelper.provider = jsonPortal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化Json文本为指定类型的对象
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="jsonText"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
public static T Deserialize<T>(string jsonText)
|
||||
{
|
||||
return provider.Deserialize<T>(jsonText);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化Json文本为指定类型的对象
|
||||
/// </summary>
|
||||
/// <param name="jsonText"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static object Deserialize(string jsonText, Type type)
|
||||
{
|
||||
return provider.Deserialize(jsonText, type);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析Json文本为IJsonToken对象
|
||||
/// </summary>
|
||||
/// <param name="json"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
public static IJsonToken Parse(string json)
|
||||
{
|
||||
return provider.Parse(json);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将对象序列化为Json文本
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static string Serialize(object obj)
|
||||
{
|
||||
return provider.Serialize(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个Json对象,使用字典初始化
|
||||
/// </summary>
|
||||
/// <param name="init"></param>
|
||||
/// <returns></returns>
|
||||
public static IJsonToken Object(Action<Dictionary<string, object>> init)
|
||||
{
|
||||
var dict = new Dictionary<string, object>();
|
||||
@@ -52,11 +81,21 @@ namespace Serein.Library.Utils
|
||||
return provider.CreateObject(dict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个Json对象,使用字典初始化
|
||||
/// </summary>
|
||||
/// <param name="values"></param>
|
||||
/// <returns></returns>
|
||||
public static IJsonToken Array(IEnumerable<object> values)
|
||||
{
|
||||
return provider.CreateArray(values);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将对象转换为JsonToken
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static IJsonToken FromObject(object obj)
|
||||
{
|
||||
if (obj is System.Collections.IEnumerable && !(obj is string))
|
||||
|
||||
@@ -32,6 +32,14 @@ namespace Serein.Library.Utils
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步选择器,返回一个新的集合,其中每个元素都是通过异步方法转换的结果。
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource"></typeparam>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="method"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<IEnumerable<TResult>> SelectAsync<TSource, TResult>(this IEnumerable<TSource> source,
|
||||
Func<TSource, Task<TResult>> method)
|
||||
{
|
||||
@@ -39,6 +47,15 @@ namespace Serein.Library.Utils
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 异步选择器,返回一个新的集合,其中每个元素都是通过异步方法转换的结果。
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource"></typeparam>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="method"></param>
|
||||
/// <param name="concurrency"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<IEnumerable<TResult>> SelectAsync<TSource, TResult>(this IEnumerable<TSource> source,
|
||||
Func<TSource, Task<TResult>> method,
|
||||
int concurrency = int.MaxValue)
|
||||
|
||||
@@ -28,23 +28,39 @@ namespace Serein.Library.Utils
|
||||
internal T Value;
|
||||
}
|
||||
|
||||
// 不使用System。Func{T},因为. net 2.0没有该类型。
|
||||
/// <summary>
|
||||
/// 不使用System。Func{T},因为. net 2.0没有该类型。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public delegate T Factory();
|
||||
|
||||
// 池对象的存储。第一个项存储在专用字段中,因为我们希望能够满足来自它的大多数请求。
|
||||
/// <summary>
|
||||
/// 池对象的存储。第一个项存储在专用字段中,因为我们希望能够满足来自它的大多数请求。
|
||||
/// </summary>
|
||||
private T _firstItem;
|
||||
|
||||
private readonly Element[] _items;
|
||||
|
||||
// 工厂在池的生命周期内被存储。只有当池需要扩展时,我们才调用它。
|
||||
// 与“new T()”相比,Func为实现者提供了更多的灵活性,并且比“new T()”更快。
|
||||
/// <summary>
|
||||
/// 工厂在池的生命周期内被存储。只有当池需要扩展时,我们才调用它。
|
||||
/// 与“new T()”相比,Func为实现者提供了更多的灵活性,并且比“new T()”更快。
|
||||
/// </summary>
|
||||
private readonly Factory _factory;
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的对象池实例,使用指定的工厂函数和默认大小(处理器核心数的两倍)。
|
||||
/// </summary>
|
||||
/// <param name="factory"></param>
|
||||
public ObjectPool(Factory factory)
|
||||
: this(factory, Environment.ProcessorCount * 2)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的对象池实例,使用指定的工厂函数和指定的大小。
|
||||
/// </summary>
|
||||
/// <param name="factory"></param>
|
||||
/// <param name="size"></param>
|
||||
public ObjectPool(Factory factory, int size)
|
||||
{
|
||||
Debug.Assert(size >= 1);
|
||||
@@ -52,6 +68,10 @@ namespace Serein.Library.Utils
|
||||
_items = new Element[size - 1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的实例。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private T CreateInstance()
|
||||
{
|
||||
T inst = _factory();
|
||||
@@ -82,6 +102,10 @@ namespace Serein.Library.Utils
|
||||
return inst;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 慢速分配方法,当第一个元素不可用时调用。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private T AllocateSlow()
|
||||
{
|
||||
Element[] items = _items;
|
||||
|
||||
@@ -669,6 +669,12 @@ namespace Serein.Library.Utils
|
||||
|
||||
#region 运行
|
||||
|
||||
/// <summary>
|
||||
/// 运行一个方法,方法的参数类型由IOC容器提供
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
public ISereinIOC Run<T>(Action<T> action)
|
||||
{
|
||||
var service = Get<T>();
|
||||
@@ -676,6 +682,13 @@ namespace Serein.Library.Utils
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运行一个方法,方法的参数类型由IOC容器提供
|
||||
/// </summary>
|
||||
/// <typeparam name="T1"></typeparam>
|
||||
/// <typeparam name="T2"></typeparam>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
public ISereinIOC Run<T1, T2>(Action<T1, T2> action)
|
||||
{
|
||||
var service1 = Get<T1>();
|
||||
@@ -685,6 +698,14 @@ namespace Serein.Library.Utils
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运行一个方法,方法的参数类型由IOC容器提供
|
||||
/// </summary>
|
||||
/// <typeparam name="T1"></typeparam>
|
||||
/// <typeparam name="T2"></typeparam>
|
||||
/// <typeparam name="T3"></typeparam>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
public ISereinIOC Run<T1, T2, T3>(Action<T1, T2, T3> action)
|
||||
{
|
||||
var service1 = Get<T1>();
|
||||
@@ -694,6 +715,15 @@ namespace Serein.Library.Utils
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运行一个方法,方法的参数类型由IOC容器提供
|
||||
/// </summary>
|
||||
/// <typeparam name="T1"></typeparam>
|
||||
/// <typeparam name="T2"></typeparam>
|
||||
/// <typeparam name="T3"></typeparam>
|
||||
/// <typeparam name="T4"></typeparam>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
public ISereinIOC Run<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action)
|
||||
{
|
||||
var service1 = Get<T1>();
|
||||
|
||||
Reference in New Issue
Block a user