重写了节点主动中断功能,修改了运行环境持久化注册已有实例的逻辑。

This commit is contained in:
fengjiayi
2024-12-26 22:24:44 +08:00
parent 7a6f8c407b
commit 3a7a8483e8
24 changed files with 428 additions and 563 deletions

View File

@@ -714,14 +714,7 @@ namespace Serein.Library.Api
event EnvOutHandler OnEnvOut;
#endregion
#region
/// <summary>
/// 设置输出
/// </summary>
// <param name="output"></param>
// <param name="clearMsg"></param>
///void SetConsoleOut(); // Action<string> output, Action clearMsg
#region
/// <summary>
/// 输出信息
@@ -730,21 +723,6 @@ namespace Serein.Library.Api
/// <param name="type"></param>
void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.Trivial);
///// <summary>
///// 使用JSON处理库输出对象信息
///// </summary>
///// <param name="obj"></param>
//void WriteLineObjToJson(object obj);
/// <summary>
/// 启动远程服务
/// </summary>
Task StartRemoteServerAsync(int port = 7525);
/// <summary>
/// 停止远程服务
/// </summary>
void StopRemoteServer();
/// <summary>
/// 加载项目文件
@@ -764,47 +742,60 @@ namespace Serein.Library.Api
/// <returns></returns>
Task<SereinProjectData> GetProjectInfoAsync();
/// <summary>
/// 从节点信息集合批量加载节点控件
/// </summary>
/// <param name="nodeInfos">节点集合信息</param>
/// <returns></returns>
Task LoadNodeInfosAsync(List<NodeInfo> nodeInfos);
#endregion
#region
/// <summary>
/// 启动远程服务
/// </summary>
Task StartRemoteServerAsync(int port = 7525);
/// <summary>
/// 停止远程服务
/// </summary>
void StopRemoteServer();
/// <summary>
/// (适用于远程连接后获取环境的运行状态)获取当前环境的信息
/// </summary>
/// <returns></returns>
Task<FlowEnvInfo> GetEnvInfoAsync();
/// <summary>
/// 加载远程环境
/// </summary>
/// <param name="addres">远程环境地址</param>
/// <param name="port">远程环境端口</param>
/// <param name="token">密码</param>
Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres,int port, string token);
Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token);
/// <summary>
/// 退出远程环境
/// </summary>
void ExitRemoteEnv();
/// <summary>
/// 从文件中加载Dll
/// </summary>
/// <param name="dllPath"></param>
void LoadLibrary(string dllPath);
/// <summary>
/// 移除DLL
/// (用于远程)通知节点属性变更
/// </summary>
/// <param name="assemblyFullName">程序集的名称</param>
bool TryUnloadLibrary(string assemblyFullName);
/// <summary>
/// 开始运行
/// </summary>
Task<bool> StartFlowAsync();
/// <summary>
/// 从选定的节点开始运行
/// </summary>
/// <param name="startNodeGuid"></param>
/// <param name="nodeGuid">节点Guid</param>
/// <param name="path">属性路径</param>
/// <param name="value">属性值</param>
/// <returns></returns>
Task<bool> StartAsyncInSelectNode(string startNodeGuid);
Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value);
/// <summary>
/// 结束运行
/// </summary>
Task<bool> ExitFlowAsync();
#endregion
#region
/// <summary>
/// 移动了某个节点(远程插件使用)
@@ -851,12 +842,7 @@ namespace Serein.Library.Api
ConnectionArgSourceType argSourceType,
int argIndex);
/// <summary>
/// 从节点信息集合批量加载节点控件
/// </summary>
/// <param name="List<NodeInfo>">节点集合信息</param>
/// <returns></returns>
Task LoadNodeInfosAsync(List<NodeInfo> nodeInfos);
/// <summary>
/// 创建节点
@@ -866,15 +852,6 @@ namespace Serein.Library.Api
/// <param name="methodDetailsInfo">节点绑定的方法说明</param>
Task<NodeInfo> CreateNodeAsync(NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null);
///// <summary>
///// 将节点放置在容器中/从容器中取出
///// </summary>
///// <param name="childNodeGuid">子节点(主要节点)</param>
///// <param name="parentNodeGuid">父节点</param>
///// <param name="isAssembly">是否组合(反之为分解节点组合关系)</param>
///// <returns></returns>
//Task<bool> ChangeNodeContainerChildAsync(string childNodeGuid,string parentNodeGuid,bool isAssembly);
/// <summary>
/// 将节点放置在容器中
/// </summary>
@@ -921,23 +898,21 @@ namespace Serein.Library.Api
Task<bool> RemoveNodeAsync(string nodeGuid);
/// <summary>
/// 激活未启动的全局触发器
/// 改变可选参数的数目
/// </summary>
/// <param name="nodeGuid"></param>
void ActivateFlipflopNode(string nodeGuid);
/// <summary>
/// 终结一个全局触发器,在它触发后将不会再次监听消息(表现为已经启动的触发器至少会再次处理一次消息,后面版本再修正这个非预期行为)
/// </summary>
/// <param name="nodeGuid"></param>
void TerminateFlipflopNode(string nodeGuid);
/// <param name="nodeGuid">对应的节点Guid</param>
/// <param name="isAdd">true增加参数false减少参数</param>
/// <param name="paramIndex">以哪个参数为模板进行拷贝,或删去某个参数(该参数必须为可选参数)</param>
/// <returns></returns>
Task<bool> ChangeParameter(string nodeGuid, bool isAdd, int paramIndex);
#endregion
#region
#if false
/// <summary>
/// <summary>
/// 设置节点中断
/// </summary>
/// <param name="nodeGuid">更改中断状态的节点Guid</param>
@@ -978,24 +953,7 @@ namespace Serein.Library.Api
#endif
#endregion
/// <summary>
/// (用于远程)通知节点属性变更
/// </summary>
/// <param name="nodeGuid">节点Guid</param>
/// <param name="path">属性路径</param>
/// <param name="value">属性值</param>
/// <returns></returns>
Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value);
/// <summary>
/// 改变可选参数的数目
/// </summary>
/// <param name="nodeGuid">对应的节点Guid</param>
/// <param name="isAdd">true增加参数false减少参数</param>
/// <param name="paramIndex">以哪个参数为模板进行拷贝,或删去某个参数(该参数必须为可选参数)</param>
/// <returns></returns>
Task<bool> ChangeParameter(string nodeGuid, bool isAdd, int paramIndex);
#region
/// <summary>
/// 获取方法描述信息
@@ -1016,17 +974,34 @@ namespace Serein.Library.Api
bool TryGetDelegateDetails(string assemblyName, string methodName, out DelegateDetails del);
#region
/// <summary>
/// (适用于远程连接后获取环境的运行状态)获取当前环境的信息
/// 开始运行
/// </summary>
Task<bool> StartFlowAsync();
/// <summary>
/// 从选定的节点开始运行
/// </summary>
/// <param name="startNodeGuid"></param>
/// <returns></returns>
Task<FlowEnvInfo> GetEnvInfoAsync();
#endregion
Task<bool> StartAsyncInSelectNode(string startNodeGuid);
#endregion
/// <summary>
/// 结束运行
/// </summary>
Task<bool> ExitFlowAsync();
#region
/// <summary>
/// 激活未启动的全局触发器
/// </summary>
/// <param name="nodeGuid"></param>
void ActivateFlipflopNode(string nodeGuid);
/// <summary>
/// 终结一个全局触发器,在它触发后将不会再次监听消息(表现为已经启动的触发器至少会再次处理一次消息,后面版本再修正这个非预期行为)
/// </summary>
/// <param name="nodeGuid"></param>
void TerminateFlipflopNode(string nodeGuid);
/// <summary>
/// 流程启动器调用,监视数据更新通知
@@ -1054,31 +1029,19 @@ namespace Serein.Library.Api
#endregion
#region
#region /
#region
/// <summary>
/// 添加或更新全局数据
/// 从文件中加载Dll
/// </summary>
/// <param name="keyName">数据名称</param>
/// <param name="data">数据集</param>
/// <returns></returns>
object AddOrUpdateGlobalData(string keyName, object data);
/// <param name="dllPath"></param>
void LoadLibrary(string dllPath);
/// <summary>
/// 获取全局数据
/// 移除DLL
/// </summary>
/// <param name="keyName">数据名称</param>
/// <returns></returns>
object GetGlobalData(string keyName);
#endregion
#region
/// <param name="assemblyFullName">程序集的名称</param>
bool TryUnloadLibrary(string assemblyFullName);
/// <summary>
/// 运行时加载
/// </summary>
@@ -1093,7 +1056,6 @@ namespace Serein.Library.Api
/// <param name="isRecurrence">是否递归加载</param>
void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true);
#endregion
#endregion
#region UI视觉

View File

@@ -12,7 +12,7 @@ namespace Serein.Library.Api
public interface IScriptFlowApi
{
/// <summary>
/// 当前流程
/// 当前流程运行环境
/// </summary>
IFlowEnvironment Env { get; }
/// <summary>
@@ -20,34 +20,28 @@ namespace Serein.Library.Api
/// </summary>
NodeModelBase NodeModel { get; }
/// <summary>
/// 动态流程上下文
/// </summary>
IDynamicContext Context { get; set; }
/// <summary>
/// 根据索引从入参数据获取数据
/// </summary>
/// <param name="context"></param>
/// <param name="index"></param>
/// <returns></returns>
object GetArgData(int index);
object GetArgData(IDynamicContext context, int index);
/// <summary>
/// 根据入参名称从入参数据获取数据
/// 获取流程当前传递的数据
/// </summary>
/// <param name="name"></param>
/// <param name="context"></param>
/// <returns></returns>
// object GetDataOfParams(string name);
object GetFlowData(IDynamicContext context);
/// <summary>
/// 获取全局数据
/// </summary>
/// <param name="keyName"></param>
/// <returns></returns>
object GetGlobalData(string keyName);
/// <summary>
/// 获取流程当前传递的数据
/// </summary>
/// <returns></returns>
object GetFlowData();
/// <summary>
/// 立即调用某个节点并获取其返回值
/// </summary>

View File

@@ -35,6 +35,22 @@ namespace Serein.Library.Api
/// <returns></returns>
ISereinIOC Register<TService, TImplementation>(params object[] parameters) where TImplementation : TService;
/// <summary>
/// 指定一个Key登记一个持久化的实例。
/// </summary>
/// <param name="key">登记使用的名称</param>
/// <param name="instance">实例对象</param>
/// <returns>是否注册成功</returns>
bool RegisterPersistennceInstance(string key, object instance);
/// <summary>
/// 指定一个Key登记一个实例。
/// </summary>
/// <param name="key">登记使用的名称</param>
/// <param name="instance">实例对象</param>
/// <returns>是否注册成功</returns>
bool RegisterInstance(string key, object instance);
/// <summary>
/// 获取类型的实例。如果需要获取的类型以“接口-实现类”的方式注册,请使用接口的类型。
/// </summary>
@@ -53,14 +69,7 @@ namespace Serein.Library.Api
/// <returns></returns>
T Get<T>(string key);
/// <summary>
/// 指定一个Key登记一个实例。如果实例中需要注入的依赖项需要将needInjectProperty设置为true。
/// </summary>
/// <param name="key">注入名称</param>
/// <param name="instance">实例对象</param>
/// <param name="needInjectProperty">是否需要注入依赖项</param>
/// <returns>是否注册成功</returns>
bool CustomRegisterInstance(string key, object instance, bool needInjectProperty = true);
/// <summary>
/// <para>创建实例并注入依赖项不会注册到IOC容器中。</para>

View File

@@ -1,4 +1,6 @@
using System;
using Newtonsoft.Json.Linq;
using Serein.Library.Utils;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
@@ -33,52 +35,67 @@ namespace Serein.Library
private bool _isEnable = true;
/// <summary>
/// 中断级别,暂时停止继续执行后继分支
/// 是否中断节点
/// </summary>
//[PropertyInfo]
//private InterruptClass _interruptClass = InterruptClass.None;
/// <summary>
/// 中断级别,暂时停止继续执行后继分支。
/// </summary>
[PropertyInfo(IsNotification = true, CustomCodeAtEnd = "// NodeModel?.Env?.SetNodeInterruptAsync(NodeModel?.Guid, value);")] // CustomCode = "NodeModel?.Env?.SetNodeInterruptAsync(NodeModel?.Guid, value);"
[PropertyInfo(IsNotification = true, CustomCodeAtEnd = "ChangeInterruptState(value);")] // CustomCode = "NodeModel?.Env?.SetNodeInterruptAsync(NodeModel?.Guid, value);"
private bool _isInterrupt = false;
}
/// <summary>
/// 节点中断
/// </summary>
public partial class NodeDebugSetting
{
/// <summary>
/// 取消中断的回调函数
/// </summary>
[PropertyInfo]
private Action _cancelInterruptCallback;
private Action _cancelInterrupt { get; set; }
/// <summary>
/// 取消中断
/// </summary>
public Action CancelInterrupt => _cancelInterrupt;
/// <summary>
/// 中断节点
/// </summary>
public Func<Task> _getInterruptTask;
/// <summary>
/// 中断Task(用来中断)
/// 获取中断Task
/// </summary>
[PropertyInfo]
private Func<Task> _getInterruptTask;
public Func<Task> GetInterruptTask => _getInterruptTask;
}
/// <summary>
/// 中断级别,暂时停止继续执行后继分支。
/// 改变中断状态
/// </summary>
//public enum InterruptClass
//{
// /// <summary>
// /// 不中断
// /// </summary>
// None,
// /// <summary>
// /// 分支中断,中断进入当前节点的分支。
// /// </summary>
// Branch,
// /// <summary>
// /// 全局中断,中断全局所有节点的运行。(暂未实现相关)
// /// </summary>
// Global,
//}
public void ChangeInterruptState(bool state)
{
if (state && _getInterruptTask is null)
{
// 设置获取中断的委托
_getInterruptTask = () => NodeModel.Env.IOC.Get<FlowInterruptTool>().WaitTriggerAsync(NodeModel.Guid);
}
else if (!state)
{
if (_getInterruptTask is null)
{
}
else
{
// 设置解除中断的委托
_cancelInterrupt = () => NodeModel.Env.IOC.Get<FlowInterruptTool>().InvokeTrigger(NodeModel.Guid);
_cancelInterrupt.Invoke();
_getInterruptTask = null;
}
}
}
}
}

View File

@@ -36,7 +36,6 @@ namespace Serein.Library
}
/// <summary>
/// 保存自定义信息
/// </summary>
@@ -60,21 +59,11 @@ namespace Serein.Library
/// </summary>
public virtual void Remove()
{
}
/// <summary>
/// 移除该节点
/// </summary>
public virtual void RemoveFromEnv()
{
if (this.DebugSetting.CancelInterruptCallback != null)
if (this.DebugSetting.CancelInterrupt != null)
{
this.DebugSetting.CancelInterruptCallback?.Invoke();
this.DebugSetting.CancelInterrupt?.Invoke();
}
this.DebugSetting.GetInterruptTask = null;
this.DebugSetting.NodeModel = null;
this.DebugSetting.CancelInterruptCallback = null;
this.DebugSetting = null;
foreach (var pd in this.MethodDetails.ParameterDetailss)
{
@@ -87,7 +76,7 @@ namespace Serein.Library
pd.ArgDataSourceNodeGuid = null;
pd.ExplicitTypeName = null;
}
this.MethodDetails.ParameterDetailss = null;
this.MethodDetails.ParameterDetailss = null;
this.MethodDetails.ActingInstance = null;
this.MethodDetails.NodeModel = null;
this.MethodDetails.ReturnType = null;
@@ -131,7 +120,6 @@ namespace Serein.Library
}
}
/// <summary>
/// 导出为节点信息
/// </summary>
@@ -231,10 +219,6 @@ namespace Serein.Library
}
#endregion
#region
#endregion
#region
/// <summary>
@@ -243,15 +227,13 @@ namespace Serein.Library
public void CancelInterrupt()
{
this.DebugSetting.IsInterrupt = false;
DebugSetting.CancelInterruptCallback?.Invoke();
DebugSetting.CancelInterrupt?.Invoke();
}
#endregion
#region
/// <summary>
/// 是否应该退出执行
/// </summary>
@@ -271,6 +253,7 @@ namespace Serein.Library
{
return true;
}
// 如果存在全局触发器,且触发器的执行任务已经被取消时,退出执行。
if (flowCts != null)
{
@@ -365,15 +348,21 @@ namespace Serein.Library
/// <returns>节点传回数据对象</returns>
public virtual async Task<object> ExecutingAsync(IDynamicContext context)
{
//if(context.NextOrientation == ConnectionInvokeType.IsError)
//{
//}
#region
if (DebugSetting.IsInterrupt) // 执行触发检查是否需要中
#region
if(context.NextOrientation == ConnectionInvokeType.IsError)
{
//var cancelType = await this.DebugSetting.GetInterruptTask(); // 等待中断结束
await Console.Out.WriteLineAsync($"[{this.MethodDetails?.MethodName}]中断已取消,开始执行后继分支");
}
// 执行触发检查是否需要中断
if (DebugSetting.IsInterrupt)
{
context.Env.TriggerInterrupt(Guid, "", InterruptTriggerEventArgs.InterruptTriggerType.Monitor); // 通知运行环境该节点中断了
await DebugSetting.GetInterruptTask.Invoke();
//await fit.WaitTriggerAsync(Guid); // 创建一个等待的中断任务
SereinEnv.WriteLine(InfoType.INFO, $"[{this.MethodDetails?.MethodName}]中断已取消,开始执行后继分支");
var flowCts = context.Env.IOC.Get<CancellationTokenSource>(NodeStaticConfig.FlipFlopCtsName);
if (IsBradk(context, flowCts)) return null; // 流程已终止,取消后续的执行
}
#endregion
@@ -405,9 +394,10 @@ namespace Serein.Library
{
if (MethodDetails.ParameterDetailss.Length == 0)
{
return new object[0];// md.ActingInstance
return new object[0]; // 无参数
}
#region
object[] args;
Array paramsArgs = null; // 初始化可选参数
int paramsArgIndex = 0; // 可选参数下标,与 object[] paramsArgs 一起使用
@@ -423,13 +413,16 @@ namespace Serein.Library
{
// 不存在可选参数
args = new object[MethodDetails.ParameterDetailss.Length]; // 调用方法的入参数组
}
}
#endregion
// 常规参数的获取
for (int i = 0; i < args.Length; i++) {
var pd = MethodDetails.ParameterDetailss[i];
args[i] = await pd.ToMethodArgData(context); // 获取数据
}
// 可选参数的获取
if(MethodDetails.ParamsArgIndex >= 0)
{
for (int i = 0; i < paramsArgs.Length; i++)
@@ -440,11 +433,13 @@ namespace Serein.Library
}
args[args.Length - 1] = paramsArgs;
}
return args;
}
/// <summary>
/// 更新节点数据,并检查监视表达式是否生效
/// </summary>
@@ -518,26 +513,6 @@ namespace Serein.Library
//}
}
///// <summary>
///// 释放对象
///// </summary>
//public void ReleaseFlowData()
//{
// if (typeof(IDisposable).IsAssignableFrom(FlowData?.GetType()) && FlowData is IDisposable disposable)
// {
// disposable?.Dispose();
// }
// this.FlowData = null;
//}
///// <summary>
///// 获取节点数据
///// </summary>
///// <returns></returns>
//public object GetFlowData()
//{
// return this.FlowData;
//}
#endregion
}

View File

@@ -0,0 +1,85 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Subjects;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Library.Utils
{
/// <summary>
/// 流程运行中断工具
/// </summary>
public class FlowInterruptTool
{
// 使用并发字典管理每个信号对应的广播列表
private readonly ConcurrentDictionary<string, Subject<bool>> _subscribers = new ConcurrentDictionary<string, Subject<bool>>();
/// <summary>
/// 获取或创建指定信号的 Subject消息广播者
/// </summary>
/// <param name="signal">枚举信号标识符</param>
/// <returns>对应的 Subject</returns>
private Subject<bool> GetOrCreateSubject(string signal)
{
return _subscribers.GetOrAdd(signal, _ => new Subject<bool>());
}
/// <summary>
/// 订阅指定信号的消息
/// </summary>
/// <param name="signal">枚举信号标识符</param>
/// <param name="action">订阅者</param>
/// <returns>取消订阅的句柄</returns>
private IDisposable Subscribe(string signal, Action<bool> action)
{
IObserver<bool> observer = new Observer<bool>(action);
var subject = GetOrCreateSubject(signal);
return subject.Subscribe(observer); // 返回取消订阅的句柄
}
/// <summary>
/// 等待触发
/// </summary>
/// <param name="signal"></param>
/// <returns></returns>
public async Task<bool> WaitTriggerAsync(string signal)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
var subscription = Subscribe(signal, taskCompletionSource.SetResult);
var result = await taskCompletionSource.Task;
subscription.Dispose(); // 取消订阅
return result;
}
/// <summary>
/// 手动触发信号,并广播给所有订阅者
/// </summary>
/// <param name="signal">枚举信号标识符</param>
/// <returns>是否成功触发</returns>
public bool InvokeTrigger(string signal)
{
if (_subscribers.TryGetValue(signal, out var subject))
{
subject.OnNext(true); // 广播给所有订阅者
subject.OnCompleted(); // 通知订阅结束
return true;
}
return false;
}
/// <summary>
/// 取消所有任务
/// </summary>
public void CancelAllTrigger()
{
foreach (var subject in _subscribers.Values)
{
subject.OnCompleted(); // 通知所有订阅者结束
}
_subscribers.Clear();
}
}
}

View File

@@ -14,147 +14,7 @@ namespace Serein.Library.Utils
{
/// <summary>
/// 信号触发器类,带有消息广播功能。
/// 使用枚举作为标记,创建
/// </summary>
public class ValueTaskFlowTrigger<TSignal>
{
// 使用并发字典管理每个信号对应的广播列表
private readonly ConcurrentDictionary<TSignal, Subject<TriggerResult<object>>> _subscribers = new ConcurrentDictionary<TSignal, Subject<TriggerResult<object>>>();
/// <summary>
/// 获取或创建指定信号的 Subject消息广播者
/// </summary>
/// <param name="signal">枚举信号标识符</param>
/// <returns>对应的 Subject</returns>
private Subject<TriggerResult<object>> GetOrCreateSubject(TSignal signal)
{
return _subscribers.GetOrAdd(signal, _ => new Subject<TriggerResult<object>>());
}
/// <summary>
/// 订阅指定信号的消息
/// </summary>
/// <param name="signal">枚举信号标识符</param>
/// <param name="observer">订阅者</param>
/// <returns>取消订阅的句柄</returns>
private IDisposable Subscribe<TResult>(TSignal signal, Action<TriggerResult<object>> action)
{
IObserver<TriggerResult<object>> observer = new Observer<TriggerResult<object>>(action);
var subject = GetOrCreateSubject(signal);
return subject.Subscribe(observer); // 返回取消订阅的句柄
}
/// <summary>
/// 等待触发器并指定超时的时间
/// </summary>
/// <typeparam name="TResult">返回值类型</typeparam>
/// <param name="signal">等待信号</param>
/// <param name="outTime">超时时间</param>
/// <returns></returns>
public async ValueTask<TriggerResult<TResult>> WaitTriggerWithTimeoutAsync<TResult>(TSignal signal, TimeSpan outTime)
{
var subject = GetOrCreateSubject(signal);
var cts = new CancellationTokenSource();
// 异步任务:超时后自动触发信号
_ = Task.Run(async () =>
{
try
{
await Task.Delay(outTime, cts.Token);
if (!cts.IsCancellationRequested) // 如果还没有被取消
{
var outResult = new TriggerResult<object>()
{
Type = TriggerDescription.Overtime
};
subject.OnNext(outResult); // 广播给所有订阅者
subject.OnCompleted(); // 通知订阅结束
}
}
catch (OperationCanceledException)
{
// 超时任务被取消
}
finally
{
cts?.Dispose(); // 确保 cts 被释放
}
}, cts.Token);
var result = await WaitTriggerAsync<TResult>(signal); // 返回一个可以超时触发的等待任务
return result;
}
/// <summary>
/// 等待触发
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="signal"></param>
/// <returns></returns>
public async ValueTask<TriggerResult<TResult>> WaitTriggerAsync<TResult>(TSignal signal)
{
var taskCompletionSource = new TaskCompletionSource<TriggerResult<object>>();
var subscription = Subscribe<TResult>(signal, taskCompletionSource.SetResult);
var result = await taskCompletionSource.Task;
subscription.Dispose(); // 取消订阅
if (result.Value is TResult data)
{
return new TriggerResult<TResult>()
{
Value = data,
Type = TriggerDescription.External,
};
}
else
{
return new TriggerResult<TResult>()
{
Type = TriggerDescription.TypeInconsistency,
};
}
}
/// <summary>
/// 手动触发信号,并广播给所有订阅者
/// </summary>
/// <typeparam name="TResult">触发类型</typeparam>
/// <param name="signal">枚举信号标识符</param>
/// <param name="value">传递的数据</param>
/// <returns>是否成功触发</returns>
public Task<bool> InvokeTriggerAsync<TResult>(TSignal signal, TResult value)
{
if (_subscribers.TryGetValue(signal, out var subject))
{
var result = new TriggerResult<object>()
{
Type = TriggerDescription.External,
Value = value
};
subject.OnNext(result); // 广播给所有订阅者
subject.OnCompleted(); // 通知订阅结束
return Task.FromResult(true);
}
return Task.FromResult(false);
}
/// <summary>
/// 取消所有任务
/// </summary>
public void CancelAllTrigger()
{
foreach (var subject in _subscribers.Values)
{
subject.OnCompleted(); // 通知所有订阅者结束
}
_subscribers.Clear();
}
}

View File

@@ -23,7 +23,7 @@ namespace Serein.Library.Utils
{
// 使用并发字典管理每个信号对应的广播列表
private readonly ConcurrentDictionary<TSignal, Subject<TriggerResult<object>>> _subscribers = new ConcurrentDictionary<TSignal, Subject<TriggerResult<object>>>();
private readonly TriggerResultPool _triggerResultPool = new TriggerResultPool();
private readonly TriggerResultPool<object> _triggerResultPool = new TriggerResultPool<object>();
/// <summary>
/// 获取或创建指定信号的 Subject消息广播者
/// </summary>

View File

@@ -76,18 +76,18 @@ namespace Serein.Library.Utils
/// 使用 ObjectPool 来复用 TriggerResult 对象
/// </summary>
// 示例 TriggerResult 对象池
public class TriggerResultPool
public class TriggerResultPool<TResult>
{
private readonly ConcurrentExpandingObjectPool<TriggerResult<object>> _objectPool;
private readonly ConcurrentExpandingObjectPool<TriggerResult<TResult>> _objectPool;
public TriggerResultPool(int defaultCapacity = 30)
{
_objectPool = new ConcurrentExpandingObjectPool<TriggerResult<object>>(defaultCapacity);
_objectPool = new ConcurrentExpandingObjectPool<TriggerResult<TResult>>(defaultCapacity);
}
public TriggerResult<object> Get() => _objectPool.Get();
public TriggerResult<TResult> Get() => _objectPool.Get();
public void Return(TriggerResult<object> result) => _objectPool.Return(result);
public void Return(TriggerResult<TResult> result) => _objectPool.Return(result);
}

View File

@@ -107,12 +107,20 @@ namespace Serein.Library.Utils
#region
/// <summary>
/// 指定key值注册一个已经实例化的实例对象
/// 指定key值注册一个已经实例化的实例对象,并持久化储存
/// </summary>
/// <param name="key"></param>
/// <param name="instance"></param>
/// <param name="needInjectProperty"></param>
public bool CustomRegisterInstance(string key, object instance, bool needInjectProperty = true)
public bool RegisterInstance(string key, object instance)
{
return RegisterPersistennceInstance(key, instance);
}
/// <summary>
/// 指定key值注册一个已经实例化的实例对象并持久化储存
/// </summary>
/// <param name="key"></param>
/// <param name="instance"></param>
public bool RegisterPersistennceInstance(string key, object instance)
{
// 不存在时才允许创建
if (_dependencies.ContainsKey(key))
@@ -120,11 +128,11 @@ namespace Serein.Library.Utils
return false;
}
_dependencies.TryAdd(key, instance);
if (needInjectProperty)
{
InjectDependencies(instance); // 注入实例需要的依赖项
}
InjectUnfinishedDependencies(key, instance); // 检查是否存在其它实例需要该类型
//if (needInjectProperty)
//{
// InjectDependencies(instance); // 注入实例需要的依赖项
//}
//InjectUnfinishedDependencies(key, instance); // 检查是否存在其它实例需要该类型
OnIOCMembersChanged?.Invoke(new IOCMembersChangedEventArgs(key, instance));
return true;
}