diff --git a/Library.Framework/Serein.Library.Framework.1.0.0.nupkg b/Library.Framework/Serein.Library.Framework.1.0.0.nupkg deleted file mode 100644 index 39614c0..0000000 Binary files a/Library.Framework/Serein.Library.Framework.1.0.0.nupkg and /dev/null differ diff --git a/Library.Framework/Serein.Library.Framework.nuspec b/Library.Framework/Serein.Library.Framework.nuspec deleted file mode 100644 index 2b0cebb..0000000 --- a/Library.Framework/Serein.Library.Framework.nuspec +++ /dev/null @@ -1,16 +0,0 @@ - - - - Serein.Library.Framework - 1.0.0 - fengjiayi - fengjiayi - false - MIT - - https://github.com/fhhyyp/serein-flow - 基于WPF(Dotnet 8)的流程可视化编辑器的依赖库 - $copyright$ - SereinFow - - \ No newline at end of file diff --git a/Library/Entity/Base/NodeModelBaseData.cs b/Library/Entity/Base/NodeModelBaseData.cs deleted file mode 100644 index b85c0dc..0000000 --- a/Library/Entity/Base/NodeModelBaseData.cs +++ /dev/null @@ -1,225 +0,0 @@ -using Serein.Library.Api; -using Serein.Library.Entity; -using Serein.Library.Enums; -using System; -using System.Collections.Generic; -using System.Threading; - -namespace Serein.NodeFlow.Base -{ - /// - /// 节点基类(数据):条件控件,动作控件,条件区域,动作区域 - /// - public abstract partial class NodeModelBase : IDynamicFlowNode - { - - public NodeModelBase() - { - PreviousNodes = []; - SuccessorNodes = []; - foreach (ConnectionType ctType in NodeStaticConfig.ConnectionTypes) - { - PreviousNodes[ctType] = new List(); - SuccessorNodes[ctType] = new List(); - } - DebugSetting = new NodeDebugSetting(); - } - - - /// - /// 调试功能 - /// - public NodeDebugSetting DebugSetting { get; set; } - - /// - /// 节点对应的控件类型 - /// - public NodeControlType ControlType { get; set; } - - /// - /// 方法描述,对应DLL的方法 - /// - public MethodDetails MethodDetails { get; set; } - - /// - /// 节点guid - /// - public string Guid { get; set; } - - /// - /// 显示名称 - /// - public string DisplayName { get; set; } = string.Empty; - - /// - /// 是否为起点控件 - /// - public bool IsStart { get; set; } - - /// - /// 运行时的上一节点 - /// - public NodeModelBase PreviousNode { get; set; } - - /// - /// 不同分支的父节点 - /// - public Dictionary> PreviousNodes { get; } - - /// - /// 不同分支的子节点 - /// - public Dictionary> SuccessorNodes { get; } - - /// - /// 当前节点执行完毕后需要执行的下一个分支的类别 - /// - public ConnectionType NextOrientation { get; set; } = ConnectionType.None; - - /// - /// 运行时的异常信息(仅在 FlowState 为 Error 时存在对应值) - /// - public Exception RuningException { get; set; } = null; - - - /// - /// 控制FlowData在同一时间只会被同一个线程更改。 - /// - private readonly ReaderWriterLockSlim _flowDataLock = new ReaderWriterLockSlim(); - private object _flowData; - /// - /// 当前传递数据(执行了节点对应的方法,才会存在值)。 - /// - protected object FlowData - { - get - { - _flowDataLock.EnterReadLock(); - try - { - return _flowData; - } - finally - { - _flowDataLock.ExitReadLock(); - } - } - set - { - _flowDataLock.EnterWriteLock(); - try - { - _flowData = value; - } - finally - { - _flowDataLock.ExitWriteLock(); - } - } - } - - } - - - - - - /// - /// 节点基类(数据):条件控件,动作控件,条件区域,动作区域 - /// - //public class NodeModelBaseBuilder - //{ - // public NodeModelBaseBuilder(NodeModelBase builder) - // { - // this.ControlType = builder.ControlType; - // this.MethodDetails = builder.MethodDetails; - // this.Guid = builder.Guid; - // this.DisplayName = builder.DisplayName; - // this.IsStart = builder.IsStart; - // this.PreviousNode = builder.PreviousNode; - // this.PreviousNodes = builder.PreviousNodes; - // this.SucceedBranch = builder.SucceedBranch; - // this.FailBranch = builder.FailBranch; - // this.ErrorBranch = builder.ErrorBranch; - // this.UpstreamBranch = builder.UpstreamBranch; - // this.FlowState = builder.FlowState; - // this.RuningException = builder.RuningException; - // this.FlowData = builder.FlowData; - // } - - - - // /// - // /// 节点对应的控件类型 - // /// - // public NodeControlType ControlType { get; } - - // /// - // /// 方法描述,对应DLL的方法 - // /// - // public MethodDetails MethodDetails { get; } - - // /// - // /// 节点guid - // /// - // public string Guid { get; } - - // /// - // /// 显示名称 - // /// - // public string DisplayName { get;} - - // /// - // /// 是否为起点控件 - // /// - // public bool IsStart { get; } - - // /// - // /// 运行时的上一节点 - // /// - // public NodeModelBase? PreviousNode { get; } - - // /// - // /// 上一节点集合 - // /// - // public List PreviousNodes { get; } = []; - - // /// - // /// 下一节点集合(真分支) - // /// - // public List SucceedBranch { get; } = []; - - // /// - // /// 下一节点集合(假分支) - // /// - // public List FailBranch { get; } = []; - - // /// - // /// 异常分支 - // /// - // public List ErrorBranch { get; } = []; - - // /// - // /// 上游分支 - // /// - // public List UpstreamBranch { get; } = []; - - // /// - // /// 当前执行状态(进入真分支还是假分支,异常分支在异常中确定) - // /// - // public FlowStateType FlowState { get; set; } = FlowStateType.None; - - // /// - // /// 运行时的异常信息(仅在 FlowState 为 Error 时存在对应值) - // /// - // public Exception RuningException { get; set; } = null; - - // /// - // /// 当前传递数据(执行了节点对应的方法,才会存在值) - // /// - // public object? FlowData { get; set; } = null; - //} - - -} - diff --git a/Library/Entity/Base/NodeModelBaseFunc.cs b/Library/Entity/Base/NodeModelBaseFunc.cs deleted file mode 100644 index 610b7fd..0000000 --- a/Library/Entity/Base/NodeModelBaseFunc.cs +++ /dev/null @@ -1,457 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Serein.Library.Api; -using Serein.Library.Attributes; -using Serein.Library.Entity; -using Serein.Library.Enums; -using Serein.Library.Ex; -using Serein.Library.Utils; -using Serein.NodeFlow.Tool; -using Serein.NodeFlow.Tool.SereinExpression; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Net.Http.Headers; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Linq; -using static Serein.Library.Utils.ChannelFlowInterrupt; - -namespace Serein.NodeFlow.Base -{ - - /// - /// 节点基类(数据):条件控件,动作控件,条件区域,动作区域 - /// - public abstract partial class NodeModelBase : IDynamicFlowNode - { - - - #region 调试中断 - - - /// - /// 不再中断 - /// - public void CancelInterrupt() - { - this.DebugSetting.InterruptClass = InterruptClass.None; - DebugSetting.CancelInterruptCallback?.Invoke(); - } - - #endregion - - #region 导出/导入项目文件节点信息 - - internal abstract Parameterdata[] GetParameterdatas(); - public virtual NodeInfo ToInfo() - { - // if (MethodDetails == null) return null; - - var trueNodes = SuccessorNodes[ConnectionType.IsSucceed].Select(item => item.Guid); // 真分支 - var falseNodes = SuccessorNodes[ConnectionType.IsFail].Select(item => item.Guid);// 假分支 - var errorNodes = SuccessorNodes[ConnectionType.IsError].Select(item => item.Guid);// 异常分支 - var upstreamNodes = SuccessorNodes[ConnectionType.Upstream].Select(item => item.Guid);// 上游分支 - - // 生成参数列表 - Parameterdata[] parameterData = GetParameterdatas(); - - return new NodeInfo - { - Guid = Guid, - MethodName = MethodDetails?.MethodName, - Label = DisplayName ?? "", - Type = this.GetType().ToString(), - TrueNodes = trueNodes.ToArray(), - FalseNodes = falseNodes.ToArray(), - UpstreamNodes = upstreamNodes.ToArray(), - ParameterData = parameterData.ToArray(), - ErrorNodes = errorNodes.ToArray(), - - }; - } - - public virtual NodeModelBase LoadInfo(NodeInfo nodeInfo) - { - this.Guid = nodeInfo.Guid; - if (this.MethodDetails is not null) - { - for (int i = 0; i < nodeInfo.ParameterData.Length; i++) - { - Parameterdata? pd = nodeInfo.ParameterData[i]; - this.MethodDetails.ParameterDetailss[i].IsExplicitData = pd.State; - this.MethodDetails.ParameterDetailss[i].DataValue = pd.Value; - } - } - - return this; - } - - #endregion - - #region 节点方法的执行 - - /// - /// 是否应该退出执行 - /// - /// - /// - /// - public static bool IsBradk(IDynamicContext context, CancellationTokenSource? flowCts) - { - // 上下文不再执行 - if(context.RunState == RunState.Completion) - { - return true; - } - - // 不存在全局触发器时,流程运行状态被设置为完成,退出执行,用于打断无限循环分支。 - if (flowCts is null && context.Env.FlowState == RunState.Completion) - { - return true; - } - // 如果存在全局触发器,且触发器的执行任务已经被取消时,退出执行。 - if (flowCts is not null) - { - if (flowCts.IsCancellationRequested) - return true; - } - return false; - } - - - - /// - /// 开始执行 - /// - /// - /// - public async Task StartFlowAsync(IDynamicContext context) - { - Stack stack = new Stack(); - stack.Push(this); - var flowCts = context.Env.IOC.Get(FlowStarter.FlipFlopCtsName); - bool hasFlipflow = flowCts != null; - while (stack.Count > 0) // 循环中直到栈为空才会退出循环 - { - await Task.Delay(0); - // 从栈中弹出一个节点作为当前节点进行处理 - var currentNode = stack.Pop(); - - #region 执行相关 - - // 筛选出上游分支 - var upstreamNodes = currentNode.SuccessorNodes[ConnectionType.Upstream].ToArray(); - for (int index = 0; index < upstreamNodes.Length; index++) - { - NodeModelBase? upstreamNode = upstreamNodes[index]; - if (upstreamNode is not null && upstreamNode.DebugSetting.IsEnable) - { - if (upstreamNode.DebugSetting.InterruptClass != InterruptClass.None) // 执行触发前 - { - var cancelType = await upstreamNode.DebugSetting.GetInterruptTask(); - await Console.Out.WriteLineAsync($"[{upstreamNode.MethodDetails?.MethodName}]中断已{cancelType},开始执行后继分支"); - } - upstreamNode.PreviousNode = currentNode; - await upstreamNode.StartFlowAsync(context); // 执行流程节点的上游分支 - if (upstreamNode.NextOrientation == ConnectionType.IsError) - { - // 如果上游分支执行失败,不再继续执行 - // 使上游节点(仅上游节点本身,不包含上游节点的后继节点) - // 具备通过抛出异常中断流程的能力 - break; - } - } - } - if (IsBradk(context, flowCts)) break; // 退出执行 - // 上游分支执行完成,才执行当前节点 - object? newFlowData = await currentNode.ExecutingAsync(context); - if (IsBradk(context, flowCts)) break; // 退出执行 - - await RefreshFlowDataAndExpInterrupt(context, currentNode, newFlowData); // 执行当前节点后刷新数据 - #endregion - - - #region 执行完成 - - // 选择后继分支 - var nextNodes = currentNode.SuccessorNodes[currentNode.NextOrientation]; - - // 将下一个节点集合中的所有节点逆序推入栈中 - for (int i = nextNodes.Count - 1; i >= 0; i--) - { - // 筛选出启用的节点的节点 - if (nextNodes[i].DebugSetting.IsEnable) - { - nextNodes[i].PreviousNode = currentNode; - stack.Push(nextNodes[i]); - } - } - - #endregion - - } - } - - - /// - /// 执行节点对应的方法 - /// - /// 流程上下文 - /// 节点传回数据对象 - public virtual async Task ExecutingAsync(IDynamicContext context) - { - #region 调试中断 - - if (DebugSetting.InterruptClass != InterruptClass.None) // 执行触发检查是否需要中断 - { - var cancelType = await this.DebugSetting.GetInterruptTask(); // 等待中断结束 - await Console.Out.WriteLineAsync($"[{this.MethodDetails?.MethodName}]中断已{cancelType},开始执行后继分支"); - } - - #endregion - - MethodDetails? md = MethodDetails; - //var del = md.MethodDelegate.Clone(); - if (md is null) - { - throw new Exception($"节点{this.Guid}不存在方法信息,请检查是否需要重写节点的ExecutingAsync"); - } - if (!context.Env.TryGetDelegateDetails(md.MethodName, out var dd)) - { - throw new Exception($"节点{this.Guid}不存在对应委托"); - } - md.ActingInstance ??= context.Env.IOC.Get(md.ActingInstanceType); - object instance = md.ActingInstance; - - - object? result = null; - - try - { - object?[]? args = GetParameters(context, this, md); - result = await dd.InvokeAsync(md.ActingInstance, args); - NextOrientation = ConnectionType.IsSucceed; - return result; - } - catch (Exception ex) - { - await Console.Out.WriteLineAsync($"节点[{this.MethodDetails?.MethodName}]异常:" + ex); - NextOrientation = ConnectionType.IsError; - RuningException = ex; - return null; - } - } - - - - /// - /// 获取对应的参数数组 - /// - public static object?[]? GetParameters(IDynamicContext context, NodeModelBase nodeModel, MethodDetails md) - { - // 用正确的大小初始化参数数组 - if (md.ParameterDetailss.Length == 0) - { - return null;// md.ActingInstance - } - - object?[]? parameters = new object[md.ParameterDetailss.Length]; - var flowData = nodeModel.PreviousNode?.FlowData; // 当前传递的数据 - var previousDataType = flowData?.GetType(); - - for (int i = 0; i < parameters.Length; i++) - { - - object? inputParameter; // 存放解析的临时参数 - var ed = md.ParameterDetailss[i]; // 方法入参描述 - - - if (ed.IsExplicitData) // 判断是否使用显示的输入参数 - { - if (ed.DataValue.StartsWith("@get", StringComparison.OrdinalIgnoreCase) && flowData is not null) - { - // 执行表达式从上一节点获取对象 - inputParameter = SerinExpressionEvaluator.Evaluate(ed.DataValue, flowData, out _); - } - else - { - // 使用输入的固定值 - inputParameter = ed.DataValue; - } - } - else - { - inputParameter = flowData; // 使用上一节点的对象 - } - - // 入参存在取值转换器 - if (ed.ExplicitType.IsEnum && ed.Convertor is not null) - { - if (Enum.TryParse(ed.ExplicitType, ed.DataValue, out var resultEnum)) - { - var value = ed.Convertor(resultEnum); - if (value is not null) - { - parameters[i] = value; - continue; - } - else - { - throw new InvalidOperationException("转换器调用失败"); - } - } - } - - // 入参存在类型转换器,获取枚举转换器中记录的枚举 - if (ed.ExplicitType.IsEnum && ed.DataType != ed.ExplicitType) - { - if (Enum.TryParse(ed.ExplicitType, ed.DataValue, out var resultEnum)) // 获取对应的枚举项 - { - // 获取绑定的类型 - var type = EnumHelper.GetBoundValue(ed.ExplicitType, resultEnum, attr => attr.Value); - if (type is Type enumBindType && enumBindType is not null) - { - var value = context.Env.IOC.Instantiate(enumBindType); - if (value is not null) - { - parameters[i] = value; - continue; - } - } - } - } - - - - - - - - - if (ed.DataType.IsValueType) - { - var valueStr = inputParameter?.ToString(); - parameters[i] = valueStr.ToValueData(ed.DataType); - } - else - { - var valueStr = inputParameter?.ToString(); - parameters[i] = ed.DataType switch - { - Type t when t == typeof(string) => valueStr, - Type t when t == typeof(IDynamicContext) => context, // 上下文 - Type t when t == typeof(DateTime) => string.IsNullOrEmpty(valueStr) ? 0 : DateTime.Parse(valueStr), - - Type t when t == typeof(MethodDetails) => md, // 节点方法描述 - Type t when t == typeof(NodeModelBase) => nodeModel, // 节点实体类 - - Type t when t.IsArray => (inputParameter as Array)?.Cast().ToList(), - Type t when t.IsGenericType && t.GetGenericTypeDefinition() == typeof(List<>) => inputParameter, - _ => inputParameter, - }; - } - - - - } - return parameters; - } - - /// - /// 更新节点数据,并检查监视表达式是否生效 - /// - /// 上下文 - /// 节点Moel - /// 新的数据 - /// - public static async Task RefreshFlowDataAndExpInterrupt(IDynamicContext context, NodeModelBase nodeModel, object? newData = null) - { - string guid = nodeModel.Guid; - if (newData is not null) - { - await MonitorObjExpInterrupt(context, nodeModel, newData, 0); // 首先监视对象 - await MonitorObjExpInterrupt(context, nodeModel, newData, 1); // 然后监视节点 - nodeModel.FlowData = newData; // 替换数据 - context.AddOrUpdate(guid, nodeModel); // 上下文中更新数据 - } - } - - private static async Task MonitorObjExpInterrupt(IDynamicContext context, NodeModelBase nodeModel, object? data, int monitorType) - { - MonitorObjectEventArgs.ObjSourceType sourceType; - string? key; - if (monitorType == 0) - { - key = data?.GetType()?.FullName; - sourceType = MonitorObjectEventArgs.ObjSourceType.IOCObj; - } - else - { - key = nodeModel.Guid; - sourceType = MonitorObjectEventArgs.ObjSourceType.IOCObj; - } - if (string.IsNullOrEmpty(key)) - { - return; - } - - if (context.Env.CheckObjMonitorState(key, out List exps)) // 如果新的数据处于查看状态,通知UI进行更新?交给运行环境判断? - { - context.Env.MonitorObjectNotification(nodeModel.Guid, data, sourceType); // 对象处于监视状态,通知UI更新数据显示 - if (exps.Count > 0) - { - // 表达式环境下判断是否需要执行中断 - bool isExpInterrupt = false; - string? exp = ""; - // 判断执行监视表达式,直到为 true 时退出 - for (int i = 0; i < exps.Count && !isExpInterrupt; i++) - { - exp = exps[i]; - if (string.IsNullOrEmpty(exp)) continue; - isExpInterrupt = SereinConditionParser.To(data, exp); - } - - if (isExpInterrupt) // 触发中断 - { - InterruptClass interruptClass = InterruptClass.Branch; // 分支中断 - if (context.Env.SetNodeInterrupt(nodeModel.Guid, interruptClass)) - { - context.Env.TriggerInterrupt(nodeModel.Guid, exp, InterruptTriggerEventArgs.InterruptTriggerType.Exp); - var cancelType = await nodeModel.DebugSetting.GetInterruptTask(); - await Console.Out.WriteLineAsync($"[{data}]中断已{cancelType},开始执行后继分支"); - } - } - } - - } - } - - - /// - /// 释放对象 - /// - public void ReleaseFlowData() - { - if (typeof(IDisposable).IsAssignableFrom(FlowData?.GetType()) && FlowData is IDisposable disposable) - { - disposable?.Dispose(); - } - this.FlowData = null; - } - - /// - /// 获取节点数据 - /// - /// - public object? GetFlowData() - { - return this.FlowData; - } - #endregion - - } -} diff --git a/Library/FlowNode/Attribute.cs b/Library/FlowNode/Attribute.cs deleted file mode 100644 index f282b59..0000000 --- a/Library/FlowNode/Attribute.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Serein.Library -{ - /// - /// 标识一个类中的某些字段需要生成相应代码 - /// - [AttributeUsage(AttributeTargets.Class, Inherited = true)] - public sealed class AutoPropertyAttribute : Attribute - { - /// - /// 属性路径 - /// CustomNode : 自定义节点 - /// - public string ValuePath = string.Empty; - } - - /// - /// 自动生成环境的属性 - /// - [AttributeUsage(AttributeTargets.Field, Inherited = true)] - public sealed class PropertyInfoAttribute : Attribute - { - /// - /// 是否通知UI - /// - public bool IsNotification = false; - /// - /// 是否使用Console.WriteLine打印 - /// - public bool IsPrint = false; - /// - /// 是否禁止参数进行修改(初始化后不能再通过setter修改) - /// - public bool IsProtection = false; - } - -} diff --git a/Library/Http/Attribute.cs b/Library/Http/Attribute.cs deleted file mode 100644 index 259bdfc..0000000 --- a/Library/Http/Attribute.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System; - -namespace Serein.Library.Http -{ - /// - /// 表示参数为url中的数据(Get请求中不需要显式标注) - /// - [AttributeUsage(AttributeTargets.Parameter)] - public sealed class IsUrlDataAttribute : Attribute - { - - } - - /// - /// 表示入参参数为整个boby的数据 - /// - /// 例如:User类型含有int id、string name字段 - /// - /// ① Add(User user) - /// 请求需要传入的json为 - /// {"user":{ - /// "id":2, - /// "name":"李志忠"}} - /// - /// ② Add([Boby]User user) - /// 请求需要传入的json为 - /// {"id":2,"name":"李志忠"} - /// - /// - [AttributeUsage(AttributeTargets.Parameter)] - public sealed class IsBobyDataAttribute : Attribute - { - - } - - /// - /// 表示该控制器会被自动注册(与程序集同一命名空间,暂时不支持运行时自动加载DLL,需要手动注册) - /// - [AttributeUsage(AttributeTargets.Class)] - public sealed class AutoHostingAttribute(string url = "") : Attribute - { - public string Url { get; } = url; - } - /// - /// 表示该属性为自动注入依赖项 - /// - [AttributeUsage(AttributeTargets.Property)] - public sealed class AutoInjectionAttribute : Attribute - { - } - - - /// - /// 方法的接口类型与附加URL - /// - /// - /// 假设UserController.Add()的WebAPI特性中 - /// http是HTTP.POST - /// url被显示标明“temp” - /// 那么请求的接口是POST,URL是 - /// [http://localhost:8080]/user/add/temp - /// - /// - /// - [AttributeUsage(AttributeTargets.Method)] - - public sealed class WebApiAttribute() : Attribute - - { - public API Type ; - public string Url ; - /// - /// 方法名称不作为url的部分 - /// - public bool IsUrl; - } - [AttributeUsage(AttributeTargets.Method)] - - public sealed class ApiPostAttribute() : Attribute - - { - public string Url; - /// - /// 方法名称不作为url的部分 - /// - public bool IsUrl = true; - } - [AttributeUsage(AttributeTargets.Method)] - - public sealed class ApiGetAttribute() : Attribute - - { - public string Url; - /// - /// 方法名称不作为url的部分 - /// - public bool IsUrl = true; - } - - /*public sealed class WebApiAttribute(API http, bool isUrl = true, string url = "") : Attribute - { - public API Http { get; } = http; - public string Url { get; } = url; - /// - /// 方法名称不作为url的部分 - /// - public bool IsUrl { get; } = isUrl; - }*/ - public enum API - { - POST, - GET, - //PUT, - //DELETE - } -} diff --git a/Library/Http/ControllerBase.cs b/Library/Http/ControllerBase.cs deleted file mode 100644 index 251b100..0000000 --- a/Library/Http/ControllerBase.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; - -namespace Serein.Library.Http -{ - public class ControllerBase - { - - public string Url { get; set; } - - public string BobyData { get; set; } - - public string GetLog(Exception ex) - { - return "Url : " + Url + Environment.NewLine + - "Ex : " + ex.Message + Environment.NewLine + - "Data : " + BobyData + Environment.NewLine; - } - } -} diff --git a/Library/Http/Router.cs b/Library/Http/Router.cs deleted file mode 100644 index 0e7d352..0000000 --- a/Library/Http/Router.cs +++ /dev/null @@ -1,768 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Serein.Library.Api; -using Serein.Library.Utils; -using System; -using System.Collections; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using Enum = System.Enum; -using Type = System.Type; - -namespace Serein.Library.Http -{ - /* - Router类负责解析请求的url,url参数,boby参数 - 根据url - - web server 监听类,监听外部的请求 - router 选择对应的控制器 - agent 负责传入对应的参数,注入依赖 - - - - */ - - - /// - /// 路由注册与解析 - /// - public class Router - { - private readonly ConcurrentDictionary _controllerAutoHosting; // 存储是否实例化 - private readonly ConcurrentDictionary _controllerTypes; // 存储控制器类型 - private readonly ConcurrentDictionary _controllerInstances; // 存储控制器实例对象 - private readonly ConcurrentDictionary> _routes; // 用于存储路由信息 - - private readonly SereinIOC serviceRegistry; // 用于存储路由信息 - - //private Type PostRequest; - - public Router(ISereinIOC serviceRegistry) // 构造函数,初始化 Router 类的新实例 - { - this.serviceRegistry = serviceRegistry; - - _routes = new ConcurrentDictionary>(); // 初始化路由字典 - - _controllerAutoHosting = new ConcurrentDictionary(); // 初始化控制器实例对象字典 - _controllerTypes = new ConcurrentDictionary(); // 初始化控制器实例对象字典 - _controllerInstances = new ConcurrentDictionary(); // 初始化控制器实例对象字典 - - foreach (API method in Enum.GetValues(typeof(API))) // 遍历 HTTP 枚举类型的所有值 - { - _routes.TryAdd(method.ToString(), new ConcurrentDictionary()); // 初始化每种 HTTP 方法对应的路由字典 - } - - // 获取当前程序集 - Assembly assembly = Assembly.GetExecutingAssembly(); - - // 获取包含“Controller”名称的类型 - var controllerTypes = assembly.GetTypes() - .Where(t => t.Name.Contains("Controller")); - - Type baseAttribute = typeof(AutoHostingAttribute); - Type baseController = typeof(ControllerBase); - foreach (var controllerType in controllerTypes) - { - if (controllerType.IsSubclassOf(baseController) && controllerType.IsDefined(baseAttribute)) - { - - // 如果属于控制器,并标记了AutoHosting特性,进行自动注册 - AutoRegisterAutoController(controllerType); - } - else - { - continue; - } - } - } - - - /// - /// 自动注册 自动实例化控制器 类型 - /// - /// - public void AutoRegisterAutoController(Type controllerType) // 方法声明,用于注册并实例化控制器类型 - { - if (!controllerType.IsClass || controllerType.IsAbstract) return; // 如果不是类或者是抽象类,则直接返回 - - var autoHostingAttribute = controllerType.GetCustomAttribute(); - if (autoHostingAttribute != null) { - foreach (var method in controllerType.GetMethods()) // 遍历控制器类型的所有方法 - { - var apiGetAttribute = method.GetCustomAttribute(); - var apiPostAttribute = method.GetCustomAttribute(); - if( apiGetAttribute == null && apiPostAttribute == null ) - { - continue; - } - - - - WebApiAttribute webApiAttribute = new WebApiAttribute() - { - Type = apiGetAttribute != null ? API.GET : API.POST, - Url = apiGetAttribute != null ? apiGetAttribute.Url : apiPostAttribute.Url, - IsUrl = apiGetAttribute != null ? apiGetAttribute.IsUrl : apiPostAttribute.IsUrl, - }; - - - - if (apiPostAttribute != null) // 如果存在 WebAPIAttribute 属性 - { - var url = AddRoutesUrl(autoHostingAttribute, - webApiAttribute, - controllerType, method); - Console.WriteLine(url); - if (url == null) continue; - _controllerAutoHosting[url] = true; - _controllerTypes[url] = controllerType; - - _controllerInstances[url] = null; - - } - - - /* var routeAttribute = method.GetCustomAttribute(); // 获取方法上的 WebAPIAttribute 自定义属性 - if (routeAttribute != null) // 如果存在 WebAPIAttribute 属性 - { - var url = AddRoutesUrl(autoHostingAttribute, routeAttribute, controllerType, method); - Console.WriteLine(url); - if (url == null) continue; - _controllerAutoHosting[url] = true; - _controllerTypes[url] = controllerType; - _controllerInstances[url] = null; - }*/ - } - } - } - /// - /// 手动注册 自动实例化控制器实例 - /// - public void RegisterAutoController() // 方法声明,用于动态注册路由 - { - Type controllerType = typeof(T); // 获取控制器实例的类型 - foreach (var method in controllerType.GetMethods()) // 遍历控制器类型的所有方法 - { - var apiGetAttribute = method.GetCustomAttribute(); - var apiPostAttribute = method.GetCustomAttribute(); - if (apiGetAttribute == null && apiPostAttribute == null) - { - continue; - } - - - - WebApiAttribute webApiAttribute = new WebApiAttribute() - { - Type = apiGetAttribute != null ? API.GET : API.POST, - Url = apiGetAttribute != null ? apiGetAttribute.Url : apiPostAttribute.Url, - IsUrl = apiGetAttribute != null ? apiGetAttribute.IsUrl : apiPostAttribute.IsUrl, - }; - - - - var url = AddRoutesUrl(null, webApiAttribute, controllerType, method); - - if (url == null) continue; - _controllerAutoHosting[url] = true; - _controllerTypes[url] = controllerType; - - _controllerInstances[url] = null; - - } - } - - - /// - /// 手动注册 实例持久控制器实例 - /// - /// - public void RegisterController(TController controllerInstance) where TController : ControllerBase // 方法声明,用于动态注册路由 - { - if(controllerInstance == null) return; - Type controllerType = controllerInstance.GetType(); // 获取控制器实例的类型 - foreach (var method in controllerType.GetMethods()) // 遍历控制器类型的所有方法 - { - var apiGetAttribute = method.GetCustomAttribute(); - var apiPostAttribute = method.GetCustomAttribute(); - if (apiGetAttribute == null && apiPostAttribute == null) - { - continue; - } - - - - WebApiAttribute webApiAttribute = new WebApiAttribute() - { - Type = apiGetAttribute != null ? API.GET : API.POST, - Url = apiGetAttribute != null ? apiGetAttribute.Url : apiPostAttribute.Url, - IsUrl = apiGetAttribute != null ? apiGetAttribute.IsUrl : apiPostAttribute.IsUrl, - }; - - - - var url = AddRoutesUrl(null, webApiAttribute, controllerType, method); - - if (url == null) continue; - _controllerInstances[url] = controllerInstance; - _controllerAutoHosting[url] = false; - } - } - - /// - /// 从方法中收集路由信息 - /// - /// - public string AddRoutesUrl(AutoHostingAttribute autoHostingAttribute, WebApiAttribute webAttribute, Type controllerType, MethodInfo method) - { - string controllerName; - if (autoHostingAttribute == null || string.IsNullOrWhiteSpace(autoHostingAttribute.Url)) - { - controllerName = controllerType.Name.Replace("Controller", "").ToLower(); // 获取控制器名称并转换为小写 - } - else - { - controllerName = autoHostingAttribute.Url; - } - - var httpMethod = webAttribute.Type; // 获取 HTTP 方法 - var customUrl = webAttribute.Url; // 获取自定义 URL - - string url; - - if (webAttribute.IsUrl) - { - - if (string.IsNullOrEmpty(customUrl)) // 如果自定义 URL 为空 - { - url = $"/{controllerName}/{method.Name}".ToLower(); // 构建默认 URL - } - else - { - customUrl = CleanUrl(customUrl); - url = $"/{controllerName}/{method.Name}/{customUrl}".ToLower();// 清理自定义 URL,并构建新的 URL - } - _routes[httpMethod.ToString()].TryAdd(url, method); // 将 URL 和方法添加到对应的路由字典中 - } - else - { - if (string.IsNullOrEmpty(customUrl)) // 如果自定义 URL 为空 - { - url = $"/{controllerName}".ToLower(); // 构建默认 URL - } - else - { - customUrl = CleanUrl(customUrl); - url = $"/{controllerName}/{customUrl}".ToLower();// 清理自定义 URL,并构建新的 URL - } - _routes[httpMethod.ToString()].TryAdd(url, method); // 将 URL 和方法添加到对应的路由字典中 - } - - return url; - - } - - - /// - /// 收集路由信息 - /// - /// - public void CollectRoutes(Type controllerType) - { - string controllerName = controllerType.Name.Replace("Controller", "").ToLower(); // 获取控制器名称并转换为小写 - foreach (var method in controllerType.GetMethods()) // 遍历控制器类型的所有方法 - { - var routeAttribute = method.GetCustomAttribute(); // 获取方法上的 WebAPIAttribute 自定义属性 - if (routeAttribute != null) // 如果存在 WebAPIAttribute 属性 - { - var customUrl = routeAttribute.Url; // 获取自定义 URL - string url; - if (string.IsNullOrEmpty(customUrl)) // 如果自定义 URL 为空 - { - url = $"/api/{controllerName}/{method.Name}".ToLower(); // 构建默认 URL - } - else - { - customUrl = CleanUrl(customUrl); - url = $"/api/{controllerName}/{method.Name}/{customUrl}".ToLower();// 清理自定义 URL,并构建新的 URL - } - var httpMethod = routeAttribute.Type; // 获取 HTTP 方法 - _routes[httpMethod.ToString()].TryAdd(url, method); // 将 URL 和方法添加到对应的路由字典中 - } - } - } - - - /// - /// 解析路由,调用对应的方法 - /// - /// - /// - public async Task RouteAsync(HttpListenerContext context) - { - var request = context.Request; // 获取请求对象 - var response = context.Response; // 获取响应对象 - var url = request.Url; // 获取请求的 URL - var httpMethod = request.HttpMethod; // 获取请求的 HTTP 方法 - - var template = request.Url.AbsolutePath.ToLower(); - - - if (!_routes[httpMethod].TryGetValue(template, out MethodInfo method)) - { - return false; - } - - - - var routeValues = GetUrlData(url); // 解析 URL 获取路由参数 - - ControllerBase controllerInstance; - if (!_controllerAutoHosting[template]) - { - controllerInstance = (ControllerBase)_controllerInstances[template]; - } - else - { - - controllerInstance = (ControllerBase)serviceRegistry.Instantiate(_controllerTypes[template]);// 使用反射创建控制器实例 - - - } - - if (controllerInstance == null) - { - return false; // 未找到控制器实例 - } - - controllerInstance.Url = url.AbsolutePath; - object result; - switch (httpMethod) // 根据请求的 HTTP 方法执行不同的操作 - { - case "GET": // 如果是 GET 请求,传入方法、控制器、url参数 - result = InvokeControllerMethodWithRouteValues(method, controllerInstance, routeValues); - break; - case "POST": // POST 请求传入方法、控制器、请求体内容,url参数 - var requestBody = await ReadRequestBodyAsync(request); // 读取请求体内容 - controllerInstance.BobyData = requestBody; - var requestJObject = requestBody.FromJSON(); - - result = InvokeControllerMethod(method, controllerInstance, requestJObject, routeValues); - break; - default: - - result = null; - - break; - } - - Return(response, result); // 返回结果 - - return true; - } - - public static string GetLog(string Url, string BobyData = "") - { - return Environment.NewLine + - "Url : " + Url + Environment.NewLine + - "Data : " + BobyData + Environment.NewLine; - } - - /// - /// GET请求的控制器方法 - /// - private object InvokeControllerMethodWithRouteValues(MethodInfo method, object controllerInstance, Dictionary routeValues) - { - object[] parameters = GetMethodParameters(method, routeValues); - return InvokeMethod(method, controllerInstance, parameters); - } - - private static readonly Dictionary methodParameterCache = new Dictionary(); - /// - /// POST请求的调用控制器方法 - /// - public object InvokeControllerMethod(MethodInfo method, object controllerInstance, dynamic requestData, Dictionary routeValues) - { - object[] cachedMethodParameters; - - if (!methodParameterCache.TryGetValue(method, out ParameterInfo[] parameters)) - { - parameters = method.GetParameters(); - } - - cachedMethodParameters = new object[parameters.Length]; - - for (int i = 0; i < parameters.Length; i++) - { - string paramName = parameters[i].Name; - bool isUrlData = parameters[i].GetCustomAttribute(typeof(IsUrlDataAttribute)) != null; - bool isBobyData = parameters[i].GetCustomAttribute(typeof(IsBobyDataAttribute)) != null; - - if (isUrlData) - { - if (!string.IsNullOrEmpty(paramName) && routeValues.TryGetValue(paramName, out string value)) - { - cachedMethodParameters[i] = ConvertValue(value, parameters[i].ParameterType); - } - else - { - cachedMethodParameters[i] = null; - } - } - else if (isBobyData) - { - cachedMethodParameters[i] = ConvertValue(requestData.ToString(), parameters[i].ParameterType); - } - else - { - if (requestData.ContainsKey(paramName)) - { - if (parameters[i].ParameterType == typeof(string)) - { - cachedMethodParameters[i] = requestData[paramName].ToString(); - } - else if (parameters[i].ParameterType == typeof(bool)) - { - cachedMethodParameters[i] = requestData[paramName?.ToLower()].ToBool(); - } - else if (parameters[i].ParameterType == typeof(int)) - { - cachedMethodParameters[i] = requestData[paramName].ToInt(); - } - else if (parameters[i].ParameterType == typeof(double)) - { - cachedMethodParameters[i] = requestData[paramName].ToDouble(); - } - else - { - cachedMethodParameters[i] = ConvertValue(requestData[paramName], parameters[i].ParameterType); - } - } - else - { - cachedMethodParameters[i] = null; - } - } - } - - // 缓存方法和参数的映射 - //methodParameterCache[method] = cachedMethodParameters; - - - // 调用方法 - - return method.Invoke(controllerInstance, cachedMethodParameters); - - } - - - /// - /// 检查方法入参参数类型,返回对应的入参数组 - /// - /// - /// - /// - private object[] GetMethodParameters(MethodInfo method, Dictionary routeValues) - { - ParameterInfo[] methodParameters = method.GetParameters(); - object[] parameters = new object[methodParameters.Length]; - - for (int i = 0; i < methodParameters.Length; i++) - { - - string paramName = methodParameters[i].Name; - - - if (routeValues.TryGetValue(paramName, out string value)) - { - parameters[i] = ConvertValue(value, methodParameters[i].ParameterType); - } - else - { - - parameters[i] = null; - - } - - } - - return parameters; - } - - /*/// - /// 转为对应的类型 - /// - /// - /// - /// - private object ConvertValue(object value, Type targetType) - { - try - { - return JsonConvert.DeserializeObject(value.ToString(), targetType); - } - catch (JsonReaderException ex) - { - return value; - } - catch (JsonSerializationException ex) - { - // 如果无法转为对应的JSON对象 - int startIndex = ex.Message.IndexOf("to type '") + "to type '".Length; // 查找类型信息开始的索引 - int endIndex = ex.Message.IndexOf("'", startIndex); // 查找类型信息结束的索引 - var typeInfo = ex.Message.Substring(startIndex, endIndex - startIndex); // 提取出错类型信息,该怎么传出去? - return null; - } - catch // (Exception ex) - { - return value; - } - }*/ - /// - /// 转为对应的类型 - /// - /// - /// - /// - private object ConvertValue(string value, Type targetType) - { - if(targetType == typeof(string)) - { - return value; - } - - try - { - - return JsonConvert.DeserializeObject(value.ToString(), targetType); - - } - catch (JsonReaderException ex) - { - return value; - } - catch (JsonSerializationException ex) - { - // 如果无法转为对应的JSON对象 - int startIndex = ex.Message.IndexOf("to type '") + "to type '".Length; // 查找类型信息开始的索引 - int endIndex = ex.Message.IndexOf('\''); // 查找类型信息结束的索引 - var typeInfo = ex.Message[startIndex..endIndex]; // 提取出错类型信息,该怎么传出去? - - return null; - - } - catch // (Exception ex) - { - return value; - } - } - - /// - /// 调用控制器方法传入参数 - /// - /// 方法 - /// 控制器实例 - /// 参数列表 - /// - private static object InvokeMethod(MethodInfo method, object controllerInstance, object[] methodParameters) - { - - object result = null; - - try - { - - result = method?.Invoke(controllerInstance, methodParameters); - - } - catch (ArgumentException ex) - { - string targetType = ExtractTargetTypeFromExceptionMessage(ex.Message); - - // 如果方法调用失败 - result = new - { - error = $"函数签名类型[{targetType}]不符合", - }; - } - catch (JsonSerializationException ex) - { - - // 查找类型信息开始的索引 - int startIndex = ex.Message.IndexOf("to type '") + "to type '".Length; - // 查找类型信息结束的索引 - int endIndex = ex.Message.IndexOf('\''); - // 提取类型信息 - string typeInfo = ex.Message[startIndex..endIndex]; - } - catch (Exception ex) - { - Console.WriteLine(ex.ToString()); - } - - return result; // 调用方法并返回结果 - - } - - - /// - /// 方法声明,用于解析 URL 获取路由参数 - /// - /// - /// - private static Dictionary GetUrlData(Uri uri) - { - Dictionary routeValues = []; - - var pathParts = uri.ToString().Split('?'); // 拆分 URL,获取路径部分 - - if (pathParts.Length > 1) // 如果包含查询字符串 - { - var queryParams = HttpUtility.ParseQueryString(pathParts[1]); // 解析查询字符串 - - foreach (string key in queryParams) // 遍历查询字符串的键值对 - { - if (key == null) continue; - - routeValues[key] = queryParams[key]; // 将键值对添加到路由参数字典中 - - } - } - - return routeValues; // 返回路由参数字典 - } - - /// - /// 读取Body中的消息 - /// - /// - /// - private static async Task ReadRequestBodyAsync(HttpListenerRequest request) - { - using (Stream stream = request.InputStream) - using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) - { - return await reader.ReadToEndAsync(); - } - } - /// - /// 返回响应消息 - /// - /// - /// - private static void Return(HttpListenerResponse response, dynamic msg) - { - string resultData; - if (response != null) - { - try - { - if (msg is IEnumerable && msg is not string) - { - // If msg is a collection (e.g., array or list), serialize it as JArray - resultData = JArray.FromObject(msg).ToString(); - } - else - { - // Otherwise, serialize it as JObject - resultData = JObject.FromObject(msg).ToString(); - } - byte[] buffer = Encoding.UTF8.GetBytes(resultData); - response.ContentLength64 = buffer.Length; - response.OutputStream.Write(buffer, 0, buffer.Length); - } - catch - { - // If serialization fails, use the original message's string representation - resultData = msg.ToString(); - } - - - } - } - - /// - /// 解析JSON - /// - /// - /// - /// - private static dynamic ParseJson(string requestBody) - { - try - { - if (string.IsNullOrWhiteSpace(requestBody)) - { - throw new Exception("Invalid JSON format"); - } - return JObject.Parse(requestBody); - } - catch - { - throw new Exception("Invalid JSON format"); - } - } - - /// - /// 修正方法特性中的URL格式 - /// - /// - /// - private static string CleanUrl(string url) - { - - while (url.Length > 0 && url[0] == '/') // 去除开头的斜杠 - { - url = url[1..]; - } - - while (url.Length > 0 && url[^1] == '/') // 去除末尾的斜杠 - { - url = url[..^1]; - } - - for (int i = 0; i < url.Length - 1; i++) // 去除连续的斜杠 - { - if (url[i] == '/' && url[i + 1] == '/') - { - url = url.Remove(i, 1); - i--; - } - } - - return url; // 返回清理后的 URL - } - /// - /// 从控制器调用方法的异常中获取出出错类型的信息 - /// - /// - /// - public static string ExtractTargetTypeFromExceptionMessage(string errorMessage) - { - string targetText = "为类型“"; - int startIndex = errorMessage.IndexOf(targetText); - if (startIndex != -1) - { - startIndex += targetText.Length; - int endIndex = errorMessage.IndexOf('\''); - if (endIndex != -1) - { - return errorMessage[startIndex..endIndex]; - } - } - - - return null; - - } - } -} - diff --git a/Library/Http/WebAPIAttribute.cs b/Library/Http/WebAPIAttribute.cs deleted file mode 100644 index b1c2d13..0000000 --- a/Library/Http/WebAPIAttribute.cs +++ /dev/null @@ -1,190 +0,0 @@ -using Serein.Library.Api; -using Serein.Library.Utils; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Net; -using System.Threading.Tasks; - -namespace Serein.Library.Http -{ - - /// - /// HTTP接口监听类 - /// - public class WebServer - { - private readonly HttpListener listener; // HTTP 监听器 - private Router router; // 路由器 - private readonly RequestLimiter requestLimiter; //接口防刷 - - - - public WebServer() - - { - listener = new HttpListener(); - - requestLimiter = new RequestLimiter(5, 8); - - } - - // 启动服务器 - public WebServer Start(string prefixe, ISereinIOC serviceContainer) - { - try - { - router = new Router(serviceContainer); - if (listener.IsListening) - { - return this; - } - - if (!prefixe.Substring(prefixe.Length - 1, 1).Equals(@"/")) - { - prefixe += @"/"; - } - - - listener.Prefixes.Add(prefixe); // 添加监听前缀 - listener.Start(); // 开始监听 - - Console.WriteLine($"开始监听:{prefixe}"); - Task.Run(async () => - { - while (listener.IsListening) - { - var context = await listener.GetContextAsync(); // 获取请求上下文 - _ = Task.Run(() => ProcessRequestAsync(context)); // 处理请求) - } - }); - return this; - } - catch (HttpListenerException ex) when (ex.ErrorCode == 183) - { - return this; - } - } - - - /// - /// 处理请求 - /// - /// - /// - private async Task ProcessRequestAsync(HttpListenerContext context) - { - // 添加CORS头部 - context.Response.Headers.Add("Access-Control-Allow-Origin", "*"); - context.Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); - context.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type"); - - // 处理OPTIONS预检请求 - if (context.Request.HttpMethod == "OPTIONS") - { - context.Response.StatusCode = (int)HttpStatusCode.OK; - context.Response.Close(); - return; - } - - var isPass = await router.RouteAsync(context); // 路由解析 - if (isPass) - { - context.Response.StatusCode = (int)HttpStatusCode.OK; - context.Response.Close(); // 关闭响应 - } - else - { - context.Response.StatusCode = (int)HttpStatusCode.NotFound; - context.Response.Close(); // 关闭响应 - } - - //var isPass = requestLimiter.AllowRequest(context.Request); - //if (isPass) - //{ - // // 如果路由没有匹配,返回 404 - // router.RouteAsync(context); // 路由解析 - //} - //else - //{ - // context.Response.StatusCode = (int)HttpStatusCode.NotFound; // 返回 404 错误 - // context.Response.Close(); // 关闭响应 - //} - - // var request = context.Request; - // 获取远程终结点信息 - //var remoteEndPoint = context.Request.RemoteEndPoint; - //// 获取用户的IP地址和端口 - //IPAddress ipAddress = remoteEndPoint.Address; - //int port = remoteEndPoint.Port; - //Console.WriteLine("外部连接:" + ipAddress.ToString() + ":" + port); - } - - // 停止服务器 - public void Stop() - { - if (listener.IsListening) - { - listener?.Stop(); // 停止监听 - listener?.Close(); // 关闭监听器 - } - } - - public void RegisterAutoController() - { - //var instance = Activator.CreateInstance(typeof(T)); - router.RegisterAutoController(); - } - - /*public void RegisterRoute(T controllerInstance) - { - router.RegisterRoute(controllerInstance); - }*/ - } - /// - /// 判断访问接口的频次是否正常 - /// - public class RequestLimiter(int seconds, int maxRequests) - { - private readonly ConcurrentDictionary> requestHistory = new (); - private readonly TimeSpan interval = TimeSpan.FromSeconds(seconds); - private readonly int maxRequests = maxRequests; - - /// - /// 判断访问接口的频次是否正常 - /// - /// - public bool AllowRequest(HttpListenerRequest request) - { - var clientIp = request.RemoteEndPoint.Address.ToString(); - var clientPort = request.RemoteEndPoint.Port; - var clientKey = clientIp + ":" + clientPort; - - var now = DateTime.Now; - - // 尝试从字典中获取请求队列,不存在则创建新的队列 - var requests = requestHistory.GetOrAdd(clientKey, new Queue()); - - lock (requests) - { - // 移除超出时间间隔的请求记录 - while (requests.Count > 0 && now - requests.Peek() > interval) - { - requests.Dequeue(); - } - - // 如果请求数超过限制,拒绝请求 - if (requests.Count >= maxRequests) - { - return false; - } - - // 添加当前请求时间,并允许请求 - requests.Enqueue(now); - } - - return true; - } - } - -} diff --git a/NodeFlow/Base/NodeModelBaseData.cs b/NodeFlow/Base/NodeModelBaseData.cs deleted file mode 100644 index d89abe0..0000000 --- a/NodeFlow/Base/NodeModelBaseData.cs +++ /dev/null @@ -1,222 +0,0 @@ -using Serein.Library.Api; -using Serein.Library.Entity; -using Serein.Library.Enums; - -namespace Serein.NodeFlow.Base -{ - /// - /// 节点基类(数据):条件控件,动作控件,条件区域,动作区域 - /// - public abstract partial class NodeModelBase : IDynamicFlowNode - { - - public NodeModelBase() - { - PreviousNodes = []; - SuccessorNodes = []; - foreach (ConnectionType ctType in NodeStaticConfig.ConnectionTypes) - { - PreviousNodes[ctType] = []; - SuccessorNodes[ctType] = []; - } - DebugSetting = new NodeDebugSetting(); - } - - - /// - /// 调试功能 - /// - public NodeDebugSetting DebugSetting { get; set; } - - /// - /// 节点对应的控件类型 - /// - public NodeControlType ControlType { get; set; } - - /// - /// 方法描述,对应DLL的方法 - /// - public MethodDetails MethodDetails { get; set; } - - /// - /// 节点guid - /// - public string Guid { get; set; } - - /// - /// 显示名称 - /// - public string DisplayName { get; set; } = string.Empty; - - /// - /// 是否为起点控件 - /// - public bool IsStart { get; set; } - - /// - /// 运行时的上一节点 - /// - public NodeModelBase? PreviousNode { get; set; } - - /// - /// 不同分支的父节点 - /// - public Dictionary> PreviousNodes { get; } - - /// - /// 不同分支的子节点 - /// - public Dictionary> SuccessorNodes { get; } - - /// - /// 当前节点执行完毕后需要执行的下一个分支的类别 - /// - public ConnectionType NextOrientation { get; set; } = ConnectionType.None; - - /// - /// 运行时的异常信息(仅在 FlowState 为 Error 时存在对应值) - /// - public Exception? RuningException { get; set; } = null; - - - /// - /// 控制FlowData在同一时间只会被同一个线程更改。 - /// - private readonly ReaderWriterLockSlim _flowDataLock = new ReaderWriterLockSlim(); - private object? _flowData; - /// - /// 当前传递数据(执行了节点对应的方法,才会存在值)。 - /// - protected object? FlowData - { - get - { - _flowDataLock.EnterReadLock(); - try - { - return _flowData; - } - finally - { - _flowDataLock.ExitReadLock(); - } - } - set - { - _flowDataLock.EnterWriteLock(); - try - { - _flowData = value; - } - finally - { - _flowDataLock.ExitWriteLock(); - } - } - } - - } - - - - - - /// - /// 节点基类(数据):条件控件,动作控件,条件区域,动作区域 - /// - //public class NodeModelBaseBuilder - //{ - // public NodeModelBaseBuilder(NodeModelBase builder) - // { - // this.ControlType = builder.ControlType; - // this.MethodDetails = builder.MethodDetails; - // this.Guid = builder.Guid; - // this.DisplayName = builder.DisplayName; - // this.IsStart = builder.IsStart; - // this.PreviousNode = builder.PreviousNode; - // this.PreviousNodes = builder.PreviousNodes; - // this.SucceedBranch = builder.SucceedBranch; - // this.FailBranch = builder.FailBranch; - // this.ErrorBranch = builder.ErrorBranch; - // this.UpstreamBranch = builder.UpstreamBranch; - // this.FlowState = builder.FlowState; - // this.RuningException = builder.RuningException; - // this.FlowData = builder.FlowData; - // } - - - - // /// - // /// 节点对应的控件类型 - // /// - // public NodeControlType ControlType { get; } - - // /// - // /// 方法描述,对应DLL的方法 - // /// - // public MethodDetails MethodDetails { get; } - - // /// - // /// 节点guid - // /// - // public string Guid { get; } - - // /// - // /// 显示名称 - // /// - // public string DisplayName { get;} - - // /// - // /// 是否为起点控件 - // /// - // public bool IsStart { get; } - - // /// - // /// 运行时的上一节点 - // /// - // public NodeModelBase? PreviousNode { get; } - - // /// - // /// 上一节点集合 - // /// - // public List PreviousNodes { get; } = []; - - // /// - // /// 下一节点集合(真分支) - // /// - // public List SucceedBranch { get; } = []; - - // /// - // /// 下一节点集合(假分支) - // /// - // public List FailBranch { get; } = []; - - // /// - // /// 异常分支 - // /// - // public List ErrorBranch { get; } = []; - - // /// - // /// 上游分支 - // /// - // public List UpstreamBranch { get; } = []; - - // /// - // /// 当前执行状态(进入真分支还是假分支,异常分支在异常中确定) - // /// - // public FlowStateType FlowState { get; set; } = FlowStateType.None; - - // /// - // /// 运行时的异常信息(仅在 FlowState 为 Error 时存在对应值) - // /// - // public Exception RuningException { get; set; } = null; - - // /// - // /// 当前传递数据(执行了节点对应的方法,才会存在值) - // /// - // public object? FlowData { get; set; } = null; - //} - - -} - diff --git a/NodeFlow/Base/NodeModelBaseFunc.cs b/NodeFlow/Base/NodeModelBaseFunc.cs deleted file mode 100644 index 610b7fd..0000000 --- a/NodeFlow/Base/NodeModelBaseFunc.cs +++ /dev/null @@ -1,457 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Serein.Library.Api; -using Serein.Library.Attributes; -using Serein.Library.Entity; -using Serein.Library.Enums; -using Serein.Library.Ex; -using Serein.Library.Utils; -using Serein.NodeFlow.Tool; -using Serein.NodeFlow.Tool.SereinExpression; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Net.Http.Headers; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Linq; -using static Serein.Library.Utils.ChannelFlowInterrupt; - -namespace Serein.NodeFlow.Base -{ - - /// - /// 节点基类(数据):条件控件,动作控件,条件区域,动作区域 - /// - public abstract partial class NodeModelBase : IDynamicFlowNode - { - - - #region 调试中断 - - - /// - /// 不再中断 - /// - public void CancelInterrupt() - { - this.DebugSetting.InterruptClass = InterruptClass.None; - DebugSetting.CancelInterruptCallback?.Invoke(); - } - - #endregion - - #region 导出/导入项目文件节点信息 - - internal abstract Parameterdata[] GetParameterdatas(); - public virtual NodeInfo ToInfo() - { - // if (MethodDetails == null) return null; - - var trueNodes = SuccessorNodes[ConnectionType.IsSucceed].Select(item => item.Guid); // 真分支 - var falseNodes = SuccessorNodes[ConnectionType.IsFail].Select(item => item.Guid);// 假分支 - var errorNodes = SuccessorNodes[ConnectionType.IsError].Select(item => item.Guid);// 异常分支 - var upstreamNodes = SuccessorNodes[ConnectionType.Upstream].Select(item => item.Guid);// 上游分支 - - // 生成参数列表 - Parameterdata[] parameterData = GetParameterdatas(); - - return new NodeInfo - { - Guid = Guid, - MethodName = MethodDetails?.MethodName, - Label = DisplayName ?? "", - Type = this.GetType().ToString(), - TrueNodes = trueNodes.ToArray(), - FalseNodes = falseNodes.ToArray(), - UpstreamNodes = upstreamNodes.ToArray(), - ParameterData = parameterData.ToArray(), - ErrorNodes = errorNodes.ToArray(), - - }; - } - - public virtual NodeModelBase LoadInfo(NodeInfo nodeInfo) - { - this.Guid = nodeInfo.Guid; - if (this.MethodDetails is not null) - { - for (int i = 0; i < nodeInfo.ParameterData.Length; i++) - { - Parameterdata? pd = nodeInfo.ParameterData[i]; - this.MethodDetails.ParameterDetailss[i].IsExplicitData = pd.State; - this.MethodDetails.ParameterDetailss[i].DataValue = pd.Value; - } - } - - return this; - } - - #endregion - - #region 节点方法的执行 - - /// - /// 是否应该退出执行 - /// - /// - /// - /// - public static bool IsBradk(IDynamicContext context, CancellationTokenSource? flowCts) - { - // 上下文不再执行 - if(context.RunState == RunState.Completion) - { - return true; - } - - // 不存在全局触发器时,流程运行状态被设置为完成,退出执行,用于打断无限循环分支。 - if (flowCts is null && context.Env.FlowState == RunState.Completion) - { - return true; - } - // 如果存在全局触发器,且触发器的执行任务已经被取消时,退出执行。 - if (flowCts is not null) - { - if (flowCts.IsCancellationRequested) - return true; - } - return false; - } - - - - /// - /// 开始执行 - /// - /// - /// - public async Task StartFlowAsync(IDynamicContext context) - { - Stack stack = new Stack(); - stack.Push(this); - var flowCts = context.Env.IOC.Get(FlowStarter.FlipFlopCtsName); - bool hasFlipflow = flowCts != null; - while (stack.Count > 0) // 循环中直到栈为空才会退出循环 - { - await Task.Delay(0); - // 从栈中弹出一个节点作为当前节点进行处理 - var currentNode = stack.Pop(); - - #region 执行相关 - - // 筛选出上游分支 - var upstreamNodes = currentNode.SuccessorNodes[ConnectionType.Upstream].ToArray(); - for (int index = 0; index < upstreamNodes.Length; index++) - { - NodeModelBase? upstreamNode = upstreamNodes[index]; - if (upstreamNode is not null && upstreamNode.DebugSetting.IsEnable) - { - if (upstreamNode.DebugSetting.InterruptClass != InterruptClass.None) // 执行触发前 - { - var cancelType = await upstreamNode.DebugSetting.GetInterruptTask(); - await Console.Out.WriteLineAsync($"[{upstreamNode.MethodDetails?.MethodName}]中断已{cancelType},开始执行后继分支"); - } - upstreamNode.PreviousNode = currentNode; - await upstreamNode.StartFlowAsync(context); // 执行流程节点的上游分支 - if (upstreamNode.NextOrientation == ConnectionType.IsError) - { - // 如果上游分支执行失败,不再继续执行 - // 使上游节点(仅上游节点本身,不包含上游节点的后继节点) - // 具备通过抛出异常中断流程的能力 - break; - } - } - } - if (IsBradk(context, flowCts)) break; // 退出执行 - // 上游分支执行完成,才执行当前节点 - object? newFlowData = await currentNode.ExecutingAsync(context); - if (IsBradk(context, flowCts)) break; // 退出执行 - - await RefreshFlowDataAndExpInterrupt(context, currentNode, newFlowData); // 执行当前节点后刷新数据 - #endregion - - - #region 执行完成 - - // 选择后继分支 - var nextNodes = currentNode.SuccessorNodes[currentNode.NextOrientation]; - - // 将下一个节点集合中的所有节点逆序推入栈中 - for (int i = nextNodes.Count - 1; i >= 0; i--) - { - // 筛选出启用的节点的节点 - if (nextNodes[i].DebugSetting.IsEnable) - { - nextNodes[i].PreviousNode = currentNode; - stack.Push(nextNodes[i]); - } - } - - #endregion - - } - } - - - /// - /// 执行节点对应的方法 - /// - /// 流程上下文 - /// 节点传回数据对象 - public virtual async Task ExecutingAsync(IDynamicContext context) - { - #region 调试中断 - - if (DebugSetting.InterruptClass != InterruptClass.None) // 执行触发检查是否需要中断 - { - var cancelType = await this.DebugSetting.GetInterruptTask(); // 等待中断结束 - await Console.Out.WriteLineAsync($"[{this.MethodDetails?.MethodName}]中断已{cancelType},开始执行后继分支"); - } - - #endregion - - MethodDetails? md = MethodDetails; - //var del = md.MethodDelegate.Clone(); - if (md is null) - { - throw new Exception($"节点{this.Guid}不存在方法信息,请检查是否需要重写节点的ExecutingAsync"); - } - if (!context.Env.TryGetDelegateDetails(md.MethodName, out var dd)) - { - throw new Exception($"节点{this.Guid}不存在对应委托"); - } - md.ActingInstance ??= context.Env.IOC.Get(md.ActingInstanceType); - object instance = md.ActingInstance; - - - object? result = null; - - try - { - object?[]? args = GetParameters(context, this, md); - result = await dd.InvokeAsync(md.ActingInstance, args); - NextOrientation = ConnectionType.IsSucceed; - return result; - } - catch (Exception ex) - { - await Console.Out.WriteLineAsync($"节点[{this.MethodDetails?.MethodName}]异常:" + ex); - NextOrientation = ConnectionType.IsError; - RuningException = ex; - return null; - } - } - - - - /// - /// 获取对应的参数数组 - /// - public static object?[]? GetParameters(IDynamicContext context, NodeModelBase nodeModel, MethodDetails md) - { - // 用正确的大小初始化参数数组 - if (md.ParameterDetailss.Length == 0) - { - return null;// md.ActingInstance - } - - object?[]? parameters = new object[md.ParameterDetailss.Length]; - var flowData = nodeModel.PreviousNode?.FlowData; // 当前传递的数据 - var previousDataType = flowData?.GetType(); - - for (int i = 0; i < parameters.Length; i++) - { - - object? inputParameter; // 存放解析的临时参数 - var ed = md.ParameterDetailss[i]; // 方法入参描述 - - - if (ed.IsExplicitData) // 判断是否使用显示的输入参数 - { - if (ed.DataValue.StartsWith("@get", StringComparison.OrdinalIgnoreCase) && flowData is not null) - { - // 执行表达式从上一节点获取对象 - inputParameter = SerinExpressionEvaluator.Evaluate(ed.DataValue, flowData, out _); - } - else - { - // 使用输入的固定值 - inputParameter = ed.DataValue; - } - } - else - { - inputParameter = flowData; // 使用上一节点的对象 - } - - // 入参存在取值转换器 - if (ed.ExplicitType.IsEnum && ed.Convertor is not null) - { - if (Enum.TryParse(ed.ExplicitType, ed.DataValue, out var resultEnum)) - { - var value = ed.Convertor(resultEnum); - if (value is not null) - { - parameters[i] = value; - continue; - } - else - { - throw new InvalidOperationException("转换器调用失败"); - } - } - } - - // 入参存在类型转换器,获取枚举转换器中记录的枚举 - if (ed.ExplicitType.IsEnum && ed.DataType != ed.ExplicitType) - { - if (Enum.TryParse(ed.ExplicitType, ed.DataValue, out var resultEnum)) // 获取对应的枚举项 - { - // 获取绑定的类型 - var type = EnumHelper.GetBoundValue(ed.ExplicitType, resultEnum, attr => attr.Value); - if (type is Type enumBindType && enumBindType is not null) - { - var value = context.Env.IOC.Instantiate(enumBindType); - if (value is not null) - { - parameters[i] = value; - continue; - } - } - } - } - - - - - - - - - if (ed.DataType.IsValueType) - { - var valueStr = inputParameter?.ToString(); - parameters[i] = valueStr.ToValueData(ed.DataType); - } - else - { - var valueStr = inputParameter?.ToString(); - parameters[i] = ed.DataType switch - { - Type t when t == typeof(string) => valueStr, - Type t when t == typeof(IDynamicContext) => context, // 上下文 - Type t when t == typeof(DateTime) => string.IsNullOrEmpty(valueStr) ? 0 : DateTime.Parse(valueStr), - - Type t when t == typeof(MethodDetails) => md, // 节点方法描述 - Type t when t == typeof(NodeModelBase) => nodeModel, // 节点实体类 - - Type t when t.IsArray => (inputParameter as Array)?.Cast().ToList(), - Type t when t.IsGenericType && t.GetGenericTypeDefinition() == typeof(List<>) => inputParameter, - _ => inputParameter, - }; - } - - - - } - return parameters; - } - - /// - /// 更新节点数据,并检查监视表达式是否生效 - /// - /// 上下文 - /// 节点Moel - /// 新的数据 - /// - public static async Task RefreshFlowDataAndExpInterrupt(IDynamicContext context, NodeModelBase nodeModel, object? newData = null) - { - string guid = nodeModel.Guid; - if (newData is not null) - { - await MonitorObjExpInterrupt(context, nodeModel, newData, 0); // 首先监视对象 - await MonitorObjExpInterrupt(context, nodeModel, newData, 1); // 然后监视节点 - nodeModel.FlowData = newData; // 替换数据 - context.AddOrUpdate(guid, nodeModel); // 上下文中更新数据 - } - } - - private static async Task MonitorObjExpInterrupt(IDynamicContext context, NodeModelBase nodeModel, object? data, int monitorType) - { - MonitorObjectEventArgs.ObjSourceType sourceType; - string? key; - if (monitorType == 0) - { - key = data?.GetType()?.FullName; - sourceType = MonitorObjectEventArgs.ObjSourceType.IOCObj; - } - else - { - key = nodeModel.Guid; - sourceType = MonitorObjectEventArgs.ObjSourceType.IOCObj; - } - if (string.IsNullOrEmpty(key)) - { - return; - } - - if (context.Env.CheckObjMonitorState(key, out List exps)) // 如果新的数据处于查看状态,通知UI进行更新?交给运行环境判断? - { - context.Env.MonitorObjectNotification(nodeModel.Guid, data, sourceType); // 对象处于监视状态,通知UI更新数据显示 - if (exps.Count > 0) - { - // 表达式环境下判断是否需要执行中断 - bool isExpInterrupt = false; - string? exp = ""; - // 判断执行监视表达式,直到为 true 时退出 - for (int i = 0; i < exps.Count && !isExpInterrupt; i++) - { - exp = exps[i]; - if (string.IsNullOrEmpty(exp)) continue; - isExpInterrupt = SereinConditionParser.To(data, exp); - } - - if (isExpInterrupt) // 触发中断 - { - InterruptClass interruptClass = InterruptClass.Branch; // 分支中断 - if (context.Env.SetNodeInterrupt(nodeModel.Guid, interruptClass)) - { - context.Env.TriggerInterrupt(nodeModel.Guid, exp, InterruptTriggerEventArgs.InterruptTriggerType.Exp); - var cancelType = await nodeModel.DebugSetting.GetInterruptTask(); - await Console.Out.WriteLineAsync($"[{data}]中断已{cancelType},开始执行后继分支"); - } - } - } - - } - } - - - /// - /// 释放对象 - /// - public void ReleaseFlowData() - { - if (typeof(IDisposable).IsAssignableFrom(FlowData?.GetType()) && FlowData is IDisposable disposable) - { - disposable?.Dispose(); - } - this.FlowData = null; - } - - /// - /// 获取节点数据 - /// - /// - public object? GetFlowData() - { - return this.FlowData; - } - #endregion - - } -} diff --git a/NodeFlow/Model/SingleExpOpNode.cs b/NodeFlow/Model/SingleExpOpNode.cs index 1f33e43..09054d8 100644 --- a/NodeFlow/Model/SingleExpOpNode.cs +++ b/NodeFlow/Model/SingleExpOpNode.cs @@ -2,6 +2,7 @@ using Serein.Library.Api; using Serein.Library.Utils.SereinExpression; using System.Reactive; +using System.Reflection.Metadata; namespace Serein.NodeFlow.Model { @@ -33,17 +34,52 @@ namespace Serein.NodeFlow.Model /// public override void OnLoading() { - Console.WriteLine("SingleExpOpNode 暂未实现 OnLoading"); + var pd = new ParameterDetails + { + Index = 0, + Name = "Exp", + DataType = typeof(object), + ExplicitType = typeof(object), + IsExplicitData = false, + DataValue = string.Empty, + ArgDataSourceNodeGuid = string.Empty, + ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData, + NodeModel = this, + Convertor = null, + ExplicitTypeName = "Value", + Items = Array.Empty(), + }; + + this.MethodDetails.ParameterDetailss = new ParameterDetails[] { pd }; } - public override Task ExecutingAsync(IDynamicContext context) + public override async Task ExecutingAsync(IDynamicContext context) { - var data = context.TransmissionData(this); // 表达式节点使用上一节点数据 + object? parameter = null;// context.TransmissionData(this); // 表达式节点使用上一节点数据 + var pd = MethodDetails.ParameterDetailss[0]; + + if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData) + { + // 使用自定义节点的参数 + parameter = context.GetFlowData(pd.ArgDataSourceNodeGuid); + } + else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke) + { + // 立刻调用目标节点,然后使用其返回值 + parameter = await Env.InvokeNodeAsync(context, pd.ArgDataSourceNodeGuid); + } + else + { + // 条件节点透传上一节点的数据 + parameter = context.TransmissionData(this); + } + + try { - var newData = SerinExpressionEvaluator.Evaluate(Expression, data, out bool isChange); + var newData = SerinExpressionEvaluator.Evaluate(Expression, parameter, out bool isChange); Console.WriteLine(newData); object? result = null; if (isChange) @@ -52,7 +88,7 @@ namespace Serein.NodeFlow.Model } else { - result = data; + result = parameter; } context.NextOrientation = ConnectionInvokeType.IsSucceed; @@ -62,7 +98,7 @@ namespace Serein.NodeFlow.Model { context.NextOrientation = ConnectionInvokeType.IsError; RuningException = ex; - return Task.FromResult(data); + return parameter; } } diff --git a/NodeFlow/Tool/ExpressionHelper.cs b/NodeFlow/Tool/ExpressionHelper.cs deleted file mode 100644 index 53395fc..0000000 --- a/NodeFlow/Tool/ExpressionHelper.cs +++ /dev/null @@ -1,785 +0,0 @@ -using Serein.Library.Api; -using Serein.Library.Core.NodeFlow; -using System.Collections.Concurrent; -using System.Linq.Expressions; -using System.Reflection; - -namespace Serein.NodeFlow.Tool -{ - /// - /// 对于实例创建的表达式树反射 - /// - public static class ExpressionHelper - { - /// - /// 缓存表达式树反射方法 - /// - private static ConcurrentDictionary Cache { get; } = new ConcurrentDictionary(); - - public static List GetCacheKey() - { - return [.. Cache.Keys]; - } - - #region 基于类型的表达式反射构建委托 - - #region 属性、字段的委托创建(表达式反射) - - /// - /// 动态获取属性值 - /// - public static Delegate PropertyGetter(Type type, string propertyName) - { - string cacheKey = $"{type.FullName}.{propertyName}.Getter"; - return Cache.GetOrAdd(cacheKey, _ => CreateGetterDelegate(type, propertyName)); - } - /// - /// 动态获取属性值 - /// - private static Delegate CreateGetterDelegate(Type type, string propertyName) - { - var parameter = Expression.Parameter(typeof(object), "instance"); - var property = Expression.Property(Expression.Convert(parameter, type), propertyName); - var lambda = Expression.Lambda(Expression.Convert(property, typeof(object)), parameter); - return lambda.Compile(); - } - - /// - /// 动态设置属性值 - /// - public static Delegate PropertySetter(Type type, string propertyName) - { - string cacheKey = $"{type.FullName}.{propertyName}.Setter"; - return Cache.GetOrAdd(cacheKey, _ => CreateSetterDelegate(type, propertyName)); - } - - /// - /// 动态设置属性值 - /// - private static Delegate CreateSetterDelegate(Type type, string propertyName) - { - var parameter = Expression.Parameter(typeof(object), "instance"); - var value = Expression.Parameter(typeof(object), "value"); - var property = Expression.Property(Expression.Convert(parameter, type), propertyName); - var assign = Expression.Assign(property, Expression.Convert(value, property.Type)); - var lambda = Expression.Lambda(assign, parameter, value); - return lambda.Compile(); - } - - /// - /// 动态获取字段值 - /// - public static Delegate FieldGetter(Type type, string fieldName) - { - string cacheKey = $"{type.FullName}.{fieldName}.FieldGetter"; - return Cache.GetOrAdd(cacheKey, _ => CreateFieldGetterDelegate(type, fieldName)); - } - /// - /// 动态获取字段值 - /// - private static Delegate CreateFieldGetterDelegate(Type type, string fieldName) - { - var parameter = Expression.Parameter(typeof(object), "instance"); - var field = Expression.Field(Expression.Convert(parameter, type), fieldName); - var lambda = Expression.Lambda(Expression.Convert(field, typeof(object)), parameter); - return lambda.Compile(); - } - - /// - /// 动态设置字段值 - /// - public static Delegate FieldSetter(Type type, string fieldName) - { - string cacheKey = $"{type.FullName}.{fieldName}.FieldSetter"; - return Cache.GetOrAdd(cacheKey, _ => CreateFieldSetterDelegate(type, fieldName)); - } - /// - /// 动态设置字段值 - /// - private static Delegate CreateFieldSetterDelegate(Type type, string fieldName) - { - var parameter = Expression.Parameter(typeof(object), "instance"); - var value = Expression.Parameter(typeof(object), "value"); - var field = Expression.Field(Expression.Convert(parameter, type), fieldName); - var assign = Expression.Assign(field, Expression.Convert(value, field.Type)); - var lambda = Expression.Lambda(assign, parameter, value); - return lambda.Compile(); - } - - #endregion - - - - /// - /// 表达式树构建无参数,无返回值方法 - /// - public static Delegate MethodCaller(Type type, MethodInfo methodInfo) - { - string cacheKey = $"{type.FullName}.{methodInfo.Name}.MethodCaller"; - return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate(type, methodInfo)); - } - - /// - /// 表达式树构建无参数,无返回值方法 - /// - private static Delegate CreateMethodCallerDelegate(Type type, MethodInfo methodInfo) - { - var parameter = Expression.Parameter(typeof(object), "instance"); - var methodCall = Expression.Call(Expression.Convert(parameter, type), methodInfo); - var lambda = Expression.Lambda(methodCall, parameter); - // Action - return lambda.Compile(); - } - - /// - /// 表达式树构建无参数,有返回值方法 - /// - public static Delegate MethodCallerHaveResult(Type type, MethodInfo methodInfo) - { - string cacheKey = $"{type.FullName}.{methodInfo.Name}.MethodCallerHaveResult"; - return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateHaveResult(type, methodInfo)); - } - /// - /// 表达式树构建无参数,有返回值方法 - /// - private static Delegate CreateMethodCallerDelegateHaveResult(Type type, MethodInfo methodInfo) - { - var parameter = Expression.Parameter(typeof(object), "instance"); - var methodCall = Expression.Call(Expression.Convert(parameter, type), methodInfo); - - if(MethodDetailsHelperTmp.IsGenericTask(methodInfo.ReturnType,out var taskResult)) - { - if(taskResult is null) - { - var lambda = Expression.Lambda>(Expression.Convert(methodCall, typeof(Task)), parameter); - return lambda.Compile(); - } - else - { - var lambda = Expression.Lambda>>(Expression.Convert(methodCall, typeof(Task)), parameter); - return lambda.Compile(); - } - } - else - { - var lambda = Expression.Lambda>(Expression.Convert(methodCall, typeof(object)), parameter); - return lambda.Compile(); - } - - } - - - /// - /// 表达式树构建多个参数,无返回值的方法 - /// - public static Delegate MethodCaller(Type type, MethodInfo methodInfo, params Type[] parameterTypes) - { - string cacheKey = $"{type.FullName}.{methodInfo.Name}.MethodCaller"; - return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate(type, methodInfo, parameterTypes)); - } - - /// - /// 表达式树构建多个参数,无返回值的方法 - /// - private static Delegate CreateMethodCallerDelegate(Type type, MethodInfo methodInfo, Type[] parameterTypes) - { - /* var parameter = Expression.Parameter(typeof(object), "instance"); - - var arguments = parameterTypes.Select((t, i) => Expression.Parameter(typeof(object), $"arg{i}")).ToArray(); - - var convertedArguments = arguments.Select((arg, i) => Expression.Convert(arg, parameterTypes[i])).ToArray(); - var methodCall = Expression.Call(Expression.Convert(parameter, type), - methodInfo, - convertedArguments); - var lambda = Expression.Lambda(methodCall, new[] { parameter }.Concat(arguments)); - var tmpAction = lambda.Compile(); - - // Action - return lambda.Compile();*/ - - var instanceParam = Expression.Parameter(typeof(object), "instance"); - var argsParam = Expression.Parameter(typeof(object[]), "args"); - - // 创建参数表达式 - var convertedArgs = parameterTypes.Select((paramType, index) => - Expression.Convert(Expression.ArrayIndex(argsParam, Expression.Constant(index)), paramType) - ).ToArray(); - - - // 创建方法调用表达式 - var methodCall = Expression.Call( - Expression.Convert(instanceParam, type), - methodInfo, - convertedArgs - ); - - // 创建 lambda 表达式 - var lambda = Expression.Lambda( - methodCall, - instanceParam, - argsParam - ); - - // Func - return lambda.Compile(); - } - - /// - /// 表达式树构建多个参数,有返回值的方法 - /// - public static Delegate MethodCallerHaveResult(Type type, MethodInfo methodInfo, Type[] parameterTypes) - { - string cacheKey = $"{type.FullName}.{methodInfo.Name}.MethodCallerHaveResult"; - return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateHaveResult(type, methodInfo, parameterTypes)); - } - /// - /// 表达式树构建多个参数,有返回值的方法 - /// - private static Delegate CreateMethodCallerDelegateHaveResult(Type type, MethodInfo methodInfo, Type[] parameterTypes) - { - /*var instanceParam = Expression.Parameter(typeof(object), "instance"); - var argsParam = Expression.Parameter(typeof(object[]), "args"); - - // 创建参数表达式 - var convertedArgs = parameterTypes.Select((paramType, index) => - Expression.Convert(Expression.ArrayIndex(argsParam, Expression.Constant(index)), paramType) - ).ToArray(); - - - // 创建方法调用表达式 - var methodCall = Expression.Call( - Expression.Convert(instanceParam, type), - methodInfo, - convertedArgs - ); - - // 创建 lambda 表达式 - var lambda = Expression.Lambda( - Expression.Convert(methodCall, typeof(object)), - instanceParam, - argsParam - ); - - // Func - return lambda.Compile();*/ - - var instanceParam = Expression.Parameter(typeof(object), "instance"); - var argsParam = Expression.Parameter(typeof(object[]), "args"); - - // 创建参数表达式 - var convertedArgs = parameterTypes.Select((paramType, index) => - Expression.Convert(Expression.ArrayIndex(argsParam, Expression.Constant(index)), paramType) - ).ToArray(); - - - // 创建方法调用表达式 - var methodCall = Expression.Call( - Expression.Convert(instanceParam, type), - methodInfo, - convertedArgs - ); - - if (MethodDetailsHelperTmp.IsGenericTask(methodInfo.ReturnType, out var taskResult)) - { - if (taskResult is null) - { - var lambda = Expression.Lambda> - (Expression.Convert(methodCall, typeof(Task)), instanceParam, argsParam); - return lambda.Compile(); - } - else - { - var lambda = Expression.Lambda>> - (Expression.Convert(methodCall, typeof(Task)), instanceParam, argsParam); - return lambda.Compile(); - } - } - else - { - var lambda = Expression.Lambda> - (Expression.Convert(methodCall, typeof(object)), instanceParam, argsParam); - return lambda.Compile(); - } - - - } - - - /// - /// 表达式树构建无参数,有返回值(Task)的方法(触发器) - /// - public static Delegate MethodCallerAsync(Type type, MethodInfo methodInfo) - { - string cacheKey = $"{type.FullName}.{methodInfo.Name}.MethodCallerAsync"; - return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateAsync(type, methodInfo)); - } - /// - /// 表达式树构建无参数,有返回值(Task)的方法(触发器) - /// - private static Delegate CreateMethodCallerDelegateAsync(Type type, MethodInfo methodInfo) - { - var parameter = Expression.Parameter(typeof(object), "instance"); - var methodCall = Expression.Call(Expression.Convert(parameter, type), methodInfo); - var lambda = Expression.Lambda>>( - Expression.Convert(methodCall, typeof(Task)), parameter); - // Func> - return lambda.Compile(); - } - - - - /// - /// 表达式树构建多个参数,有返回值(Task-object)的方法(触发器) - /// - public static Delegate MethodCallerAsync(Type type, MethodInfo method, params Type[] parameterTypes) - { - - string cacheKey = $"{type.FullName}.{method.Name}.MethodCallerAsync"; - return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateAsync(type, method, parameterTypes)); - } - /// - /// 表达式树构建多个参数,有返回值(Task)的方法(触发器) - /// - private static Delegate CreateMethodCallerDelegateAsync(Type type, MethodInfo methodInfo, Type[] parameterTypes) - { - var instanceParam = Expression.Parameter(typeof(object), "instance"); - var argsParam = Expression.Parameter(typeof(object[]), "args"); - - // 创建参数表达式 - var convertedArgs = parameterTypes.Select((paramType, index) => - Expression.Convert(Expression.ArrayIndex(argsParam, Expression.Constant(index)), paramType) - ).ToArray(); - - - // 创建方法调用表达式 - var methodCall = Expression.Call( - Expression.Convert(instanceParam, type), - methodInfo, - convertedArgs - ); - - // 创建 lambda 表达式 - var lambda = Expression.Lambda>>( - Expression.Convert(methodCall, typeof(Task)), - instanceParam, - argsParam - ); - //获取返回类型 - //var returnType = methodInfo.ReturnType; - //var lambda = Expression.Lambda( - // typeof(Func<,,>).MakeGenericType(typeof(object), typeof(object[]), returnType), - // Expression.Convert(methodCall, returnType), - // instanceParam, - // argsParam - // ); - - - //var resule = task.DynamicInvoke((object)[Activator.CreateInstance(type), [new DynamicContext(null)]]); - return lambda.Compile(); - } - - - - #region 单参数 - - /// - /// 表达式树构建单参数,无返回值的方法 - /// - public static Delegate MethodCaller(Type type, string methodName, Type parameterType) - { - string cacheKey = $"{type.FullName}.{methodName}.MethodCallerWithParam"; - return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate(type, methodName, parameterType)); - } - /// - /// 表达式树构建单参数,无返回值的方法 - /// - private static Delegate CreateMethodCallerDelegate(Type type, string methodName, Type parameterType) - { - var parameter = Expression.Parameter(typeof(object), "instance"); - var argument = Expression.Parameter(typeof(object), "argument"); - var methodCall = Expression.Call(Expression.Convert(parameter, type), - type.GetMethod(methodName, [parameterType])!, - Expression.Convert(argument, parameterType)); - var lambda = Expression.Lambda(methodCall, parameter, argument); - return lambda.Compile(); - } - - /// - /// 表达式树构建单参数,有返回值的方法 - /// - public static Delegate MethodCallerWithResult(Type type, string methodName, Type parameterType, Type returnType) - { - string cacheKey = $"{type.FullName}.{methodName}.MethodCallerWithResult"; - return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateWithResult(type, methodName, parameterType, returnType)); - } - /// - /// 表达式树构建单参数,有返回值的方法 - /// - private static Delegate CreateMethodCallerDelegateWithResult(Type type, string methodName, Type parameterType, Type returnType) - { - var parameter = Expression.Parameter(typeof(object), "instance"); - var argument = Expression.Parameter(typeof(object), "argument"); - var methodCall = Expression.Call(Expression.Convert(parameter, type), - type.GetMethod(methodName, [parameterType])!, - Expression.Convert(argument, parameterType)); - var lambda = Expression.Lambda(Expression.Convert(methodCall, typeof(object)), parameter, argument); - - - return lambda.Compile(); - } - - #endregion - - #endregion - - - #region 泛型表达式反射构建方法(已注释) - /* - - - /// - /// 动态获取属性值 - /// - /// - /// - /// - /// - public static Func PropertyGetter(string propertyName) - { - string cacheKey = $"{typeof(T).FullName}.{propertyName}.Getter"; - return (Func)Cache.GetOrAdd(cacheKey, _ => CreateGetterDelegate(propertyName)); - } - - private static Func CreateGetterDelegate(string propertyName) - { - var parameter = Expression.Parameter(typeof(T), "instance"); - var property = Expression.Property(parameter, propertyName); - var lambda = Expression.Lambda>(property, parameter); - return lambda.Compile(); - } - - /// - /// 动态设置属性值 - /// - /// - /// - /// - /// - public static Action PropertySetter(string propertyName) - { - string cacheKey = $"{typeof(T).FullName}.{propertyName}.Setter"; - return (Action)Cache.GetOrAdd(cacheKey, _ => CreateSetterDelegate(propertyName)); - } - - private static Action CreateSetterDelegate(string propertyName) - { - var parameter = Expression.Parameter(typeof(T), "instance"); - var value = Expression.Parameter(typeof(TProperty), "value"); - var property = Expression.Property(parameter, propertyName); - var assign = Expression.Assign(property, value); - var lambda = Expression.Lambda>(assign, parameter, value); - return lambda.Compile(); - } - - /// - /// 动态获取字段值 - /// - /// - /// - /// - /// - public static Func FieldGetter(string fieldName) - { - string cacheKey = $"{typeof(T).FullName}.{fieldName}.FieldGetter"; - return (Func)Cache.GetOrAdd(cacheKey, _ => CreateFieldGetterDelegate(fieldName)); - } - - private static Func CreateFieldGetterDelegate(string fieldName) - { - var parameter = Expression.Parameter(typeof(T), "instance"); - var field = Expression.Field(parameter, fieldName); - var lambda = Expression.Lambda>(field, parameter); - return lambda.Compile(); - } - - /// - /// 动态设置字段值 - /// - /// - /// - /// - /// - public static Action FieldSetter(string fieldName) - { - string cacheKey = $"{typeof(T).FullName}.{fieldName}.FieldSetter"; - return (Action)Cache.GetOrAdd(cacheKey, _ => CreateFieldSetterDelegate(fieldName)); - } - - private static Action CreateFieldSetterDelegate(string fieldName) - { - var parameter = Expression.Parameter(typeof(T), "instance"); - var value = Expression.Parameter(typeof(TField), "value"); - var field = Expression.Field(parameter, fieldName); - var assign = Expression.Assign(field, value); - var lambda = Expression.Lambda>(assign, parameter, value); - return lambda.Compile(); - } - - - - - - /// - /// 动态调用无参数方法 - /// - /// - /// - /// - public static Action MethodCaller(string methodName) - { - string cacheKey = $"{typeof(T).FullName}.{methodName}.MethodCaller"; - return (Action)Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate(methodName)); - } - - private static Action CreateMethodCallerDelegate(string methodName) - { - var parameter = Expression.Parameter(typeof(T), "instance"); - var methodCall = Expression.Call(parameter, typeof(T).GetMethod(methodName)); - var lambda = Expression.Lambda>(methodCall, parameter); - return lambda.Compile(); - } - - /// - /// 动态调用无参有返回值方法 - /// - /// - /// - /// - /// - public static Func MethodCallerHaveResul(string methodName) - { - string cacheKey = $"{typeof(T).FullName}.{methodName}.MethodCaller"; - return (Func)Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateHaveResult(methodName)); - } - - private static Func CreateMethodCallerDelegateHaveResult(string methodName) - { - var parameter = Expression.Parameter(typeof(T), "instance"); - var methodCall = Expression.Call(parameter, typeof(T).GetMethod(methodName)); - var lambda = Expression.Lambda>(methodCall, parameter); - return lambda.Compile(); - } - - - /// - /// 动态调用单参数无返回值的方法 - /// - /// - /// - /// - /// - public static Action MethodCaller(string methodName) - { - string cacheKey = $"{typeof(T).FullName}.{methodName}.MethodCallerWithParam"; - return (Action)Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate(methodName)); - } - - private static Action CreateMethodCallerDelegate(string methodName) - { - var parameter = Expression.Parameter(typeof(T), "instance"); - var argument = Expression.Parameter(typeof(TParam), "argument"); - var methodCall = Expression.Call(parameter, typeof(T).GetMethod(methodName), argument); - var lambda = Expression.Lambda>(methodCall, parameter, argument); - return lambda.Compile(); - } - - /// - /// 动态调用单参数有返回值的方法 - /// - /// - /// - /// - /// - /// - public static Func MethodCallerWithResult(string methodName) - { - string cacheKey = $"{typeof(T).FullName}.{methodName}.MethodCallerWithResult"; - return (Func)Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate(methodName)); - } - - private static Func CreateMethodCallerDelegate(string methodName) - { - var parameter = Expression.Parameter(typeof(T), "instance"); - var argument = Expression.Parameter(typeof(TParam), "argument"); - var methodCall = Expression.Call(parameter, typeof(T).GetMethod(methodName), argument); - var lambda = Expression.Lambda>(methodCall, parameter, argument); - return lambda.Compile(); - } - - /// - /// 动态调用多参无返回值的方法 - /// - /// - /// - /// - /// - public static Action MethodCaller(string methodName, params Type[] parameterTypes) - { - string cacheKey = $"{typeof(T).FullName}.{methodName}.MethodCaller"; - return (Action)Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate(methodName, parameterTypes)); - } - - private static Action CreateMethodCallerDelegate(string methodName, Type[] parameterTypes) - { - var parameter = Expression.Parameter(typeof(T), "instance"); - var arguments = parameterTypes.Select((type, index) => - Expression.Parameter(typeof(object), $"arg{index}") - ).ToList(); - - var convertedArguments = arguments.Select((arg, index) => - Expression.Convert(arg, parameterTypes[index]) - ).ToList(); - - var methodInfo = typeof(T).GetMethod(methodName, parameterTypes); - - if (methodInfo == null) - { - throw new ArgumentException($"Method '{methodName}' not found in type '{typeof(T).FullName}' with given parameter types."); - } - - var methodCall = Expression.Call(parameter, methodInfo, convertedArguments); - var lambda = Expression.Lambda>(methodCall, new[] { parameter }.Concat(arguments)); - return lambda.Compile(); - } - - - - /// - /// 动态调用多参有返回值的方法 - /// - /// - /// - /// - /// - /// - public static Func MethodCallerHaveResult(string methodName, Type[] parameterTypes) - { - string cacheKey = $"{typeof(T).FullName}.{methodName}.MethodCallerHaveResult"; - return (Func)Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate(methodName, parameterTypes)); - } - - private static Func CreateMethodCallerDelegate(string methodName, Type[] parameterTypes) - { - var instanceParam = Expression.Parameter(typeof(T), "instance"); - var argsParam = Expression.Parameter(typeof(object[]), "args"); - - var convertedArgs = new Expression[parameterTypes.Length]; - for (int i = 0; i < parameterTypes.Length; i++) - { - var index = Expression.Constant(i); - var argType = parameterTypes[i]; - var arrayIndex = Expression.ArrayIndex(argsParam, index); - var convertedArg = Expression.Convert(arrayIndex, argType); - convertedArgs[i] = convertedArg; - } - - var methodInfo = typeof(T).GetMethod(methodName, parameterTypes); - - if (methodInfo == null) - { - throw new ArgumentException($"Method '{methodName}' not found in type '{typeof(T).FullName}' with given parameter types."); - } - - var methodCall = Expression.Call(instanceParam, methodInfo, convertedArgs); - var lambda = Expression.Lambda>(methodCall, instanceParam, argsParam); - return lambda.Compile(); - } - - - - - - - - - */ - - #endregion - - #region 暂时不删(已注释) - /* /// - /// 表达式树构建多个参数,有返回值的方法 - /// - public static Delegate MethodCallerHaveResult(Type type, string methodName, Type[] parameterTypes) - { - string cacheKey = $"{type.FullName}.{methodName}.MethodCallerHaveResult"; - return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateHaveResult(type, methodName, parameterTypes)); - } - - private static Delegate CreateMethodCallerDelegateHaveResult(Type type, string methodName, Type[] parameterTypes) - { - var instanceParam = Expression.Parameter(typeof(object), "instance"); - var argsParam = Expression.Parameter(typeof(object[]), "args"); - var convertedArgs = parameterTypes.Select((paramType, index) => - Expression.Convert(Expression.ArrayIndex(argsParam, Expression.Constant(index)), paramType) - ).ToArray(); - var methodCall = Expression.Call(Expression.Convert(instanceParam, type), type.GetMethod(methodName, parameterTypes), convertedArgs); - var lambda = Expression.Lambda(Expression.Convert(methodCall, typeof(object)), instanceParam, argsParam); - return lambda.Compile(); - }*/ - - - - /*/// - /// 表达式反射 构建 无返回值、无参数 的委托 - /// - /// - /// - /// - /// - public static Delegate MethodCaller(Type type, string methodName, Type[] parameterTypes) - { - string cacheKey = $"{type.FullName}.{methodName}.{string.Join(",", parameterTypes.Select(t => t.FullName))}.MethodCaller"; - return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate(type, methodName, parameterTypes)); - } - - /// - /// 表达式反射 构建 无返回值、无参数 的委托 - /// - /// - /// - /// - /// - private static Delegate CreateMethodCallerDelegate(Type type, string methodName, Type[] parameterTypes) - { - var parameter = Expression.Parameter(typeof(object), "instance"); - var arguments = parameterTypes.Select((paramType, index) => Expression.Parameter(paramType, $"param{index}")).ToArray(); - var methodCall = Expression.Call(Expression.Convert(parameter, type), type.GetMethod(methodName, parameterTypes), arguments); - - var delegateType = Expression.GetActionType(new[] { typeof(object) }.Concat(parameterTypes).ToArray()); - var lambda = Expression.Lambda(delegateType, methodCall, new[] { parameter }.Concat(arguments).ToArray()); - return lambda.Compile(); - } -*/ - /*public static Delegate MethodCallerHaveResult(Type type, string methodName, Type returnType, Type[] parameterTypes) - { - string cacheKey = $"{type.FullName}.{methodName}.{string.Join(",", parameterTypes.Select(t => t.FullName))}.MethodCallerHaveResult"; - return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateHaveResult(type, methodName, returnType, parameterTypes)); - } - - private static Delegate CreateMethodCallerDelegateHaveResult(Type type, string methodName, Type returnType, Type[] parameterTypes) - { - var parameter = Expression.Parameter(typeof(object), "instance"); - var arguments = parameterTypes.Select((paramType, index) => Expression.Parameter(paramType, $"param{index}")).ToArray(); - var methodCall = Expression.Call(Expression.Convert(parameter, type), type.GetMethod(methodName, parameterTypes), arguments); - - var delegateType = Expression.GetFuncType(new[] { typeof(object) }.Concat(parameterTypes).Concat(new[] { typeof(object) }).ToArray()); - var lambda = Expression.Lambda(delegateType, Expression.Convert(methodCall, typeof(object)), new[] { parameter }.Concat(arguments).ToArray()); - return lambda.Compile(); - } - -*/ - - #endregion - } -} diff --git a/NodeFlow/Tool/SereinExpression/Resolver/BoolConditionResolver.cs b/NodeFlow/Tool/SereinExpression/Resolver/BoolConditionResolver.cs deleted file mode 100644 index f5fe3ed..0000000 --- a/NodeFlow/Tool/SereinExpression/Resolver/BoolConditionResolver.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Serein.NodeFlow.Tool.SereinExpression.Resolver -{ - public class BoolConditionResolver : SereinConditionResolver - { - public enum Operator - { - /// - /// 是 - /// - Is - } - - public Operator Op { get; set; } - public bool Value { get; set; } - - public override bool Evaluate(object obj) - { - - if (obj is bool boolObj) - { - return boolObj == Value; - /*switch (Op) - { - case Operator.Is: - return boolObj == Value; - }*/ - } - return false; - } - } - -} diff --git a/NodeFlow/Tool/SereinExpression/Resolver/MemberConditionResolver.cs b/NodeFlow/Tool/SereinExpression/Resolver/MemberConditionResolver.cs deleted file mode 100644 index db34831..0000000 --- a/NodeFlow/Tool/SereinExpression/Resolver/MemberConditionResolver.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Serein.NodeFlow.Tool.SereinExpression.Resolver -{ - public class MemberConditionResolver : SereinConditionResolver where T : struct, IComparable - { - //public string MemberPath { get; set; } - public ValueTypeConditionResolver.Operator Op { get; set; } - public object? TargetObj { get; set; } - public T Value { get; set; } - - public string ArithmeticExpression { get; set; } - public T RangeEnd { get; internal set; } - public T RangeStart { get; internal set; } - - public override bool Evaluate(object? obj) - { - //object? memberValue = GetMemberValue(obj, MemberPath); - - - if (TargetObj is T typedObj) - { - return new ValueTypeConditionResolver - { - RangeStart = RangeStart, - RangeEnd = RangeEnd, - Op = Op, - Value = Value, - ArithmeticExpression = ArithmeticExpression, - }.Evaluate(typedObj); - } - return false; - } - - //private object? GetMemberValue(object? obj, string memberPath) - //{ - // string[] members = memberPath[1..].Split('.'); - // foreach (var member in members) - // { - // if (obj == null) return null; - // Type type = obj.GetType(); - // PropertyInfo? propertyInfo = type.GetProperty(member); - // FieldInfo? fieldInfo = type.GetField(member); - // if (propertyInfo != null) - // obj = propertyInfo.GetValue(obj); - // else if (fieldInfo != null) - // obj = fieldInfo.GetValue(obj); - // else - // throw new ArgumentException($"Member {member} not found in type {type.FullName}"); - // } - // return obj; - //} - } - -} diff --git a/NodeFlow/Tool/SereinExpression/Resolver/MemberStringConditionResolver.cs b/NodeFlow/Tool/SereinExpression/Resolver/MemberStringConditionResolver.cs deleted file mode 100644 index ef9493f..0000000 --- a/NodeFlow/Tool/SereinExpression/Resolver/MemberStringConditionResolver.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace Serein.NodeFlow.Tool.SereinExpression.Resolver -{ - public class MemberStringConditionResolver : SereinConditionResolver - { - public string MemberPath { get; set; } - - public StringConditionResolver.Operator Op { get; set; } - - public string Value { get; set; } - - - public override bool Evaluate(object obj) - { - object memberValue; - if (!string.IsNullOrWhiteSpace(MemberPath)) - { - memberValue = GetMemberValue(obj, MemberPath); - } - else - { - memberValue = obj; - } - - if (memberValue is string strObj) - { - return new StringConditionResolver - { - Op = Op, - Value = Value - }.Evaluate(strObj); - } - return false; - } - - private object? GetMemberValue(object? obj, string memberPath) - { - string[] members = memberPath[1..].Split('.'); - foreach (var member in members) - { - - if (obj is null) return null; - - Type type = obj.GetType(); - PropertyInfo? propertyInfo = type.GetProperty(member); - FieldInfo? fieldInfo = type.GetField(member); - if (propertyInfo != null) - obj = propertyInfo.GetValue(obj); - else if (fieldInfo != null) - obj = fieldInfo.GetValue(obj); - else - throw new ArgumentException($"Member {member} not found in type {type.FullName}"); - } - - return obj; - - } - - - private static string GetArithmeticExpression(string part) - { - int startIndex = part.IndexOf('['); - int endIndex = part.IndexOf(']'); - if (startIndex >= 0 && endIndex > startIndex) - { - return part.Substring(startIndex + 1, endIndex - startIndex - 1); - } - - return null; - - } - - - - - - } - -} diff --git a/NodeFlow/Tool/SereinExpression/Resolver/PassConditionResolver.cs b/NodeFlow/Tool/SereinExpression/Resolver/PassConditionResolver.cs deleted file mode 100644 index 5a30e7e..0000000 --- a/NodeFlow/Tool/SereinExpression/Resolver/PassConditionResolver.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Serein.NodeFlow.Tool.SereinExpression.Resolver -{ - public class PassConditionResolver : SereinConditionResolver - { - public Operator Op { get; set; } - public override bool Evaluate(object obj) - { - /*return Op switch - { - Operator.Pass => true, - Operator.NotPass => false, - _ => throw new NotSupportedException("不支持的条件类型") - };*/ - switch (Op) - { - case Operator.Pass: - return true; - case Operator.NotPass: - return false; - default: - throw new NotSupportedException("不支持的条件类型"); - - } - } - - public enum Operator - { - Pass, - NotPass, - } - } -} diff --git a/NodeFlow/Tool/SereinExpression/Resolver/StringConditionResolver.cs b/NodeFlow/Tool/SereinExpression/Resolver/StringConditionResolver.cs deleted file mode 100644 index 7e2d178..0000000 --- a/NodeFlow/Tool/SereinExpression/Resolver/StringConditionResolver.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Serein.NodeFlow.Tool.SereinExpression.Resolver -{ - public class StringConditionResolver : SereinConditionResolver - { - public enum Operator - { - /// - /// 出现过 - /// - Contains, - /// - /// 没有出现过 - /// - DoesNotContain, - /// - /// 相等 - /// - Equal, - /// - /// 不相等 - /// - NotEqual, - /// - /// 起始字符串等于 - /// - StartsWith, - /// - /// 结束字符串等于 - /// - EndsWith - } - - public Operator Op { get; set; } - - public string Value { get; set; } - - - public override bool Evaluate(object obj) - { - if (obj is string strObj) - { - /*return Op switch - { - Operator.Contains => strObj.Contains(Value), - Operator.DoesNotContain => !strObj.Contains(Value), - Operator.Equal => strObj == Value, - Operator.NotEqual => strObj != Value, - Operator.StartsWith => strObj.StartsWith(Value), - Operator.EndsWith => strObj.EndsWith(Value), - _ => throw new NotSupportedException("不支持的条件类型"), - };*/ - - switch (Op) - { - case Operator.Contains: - return strObj.Contains(Value); - case Operator.DoesNotContain: - return !strObj.Contains(Value); - case Operator.Equal: - return strObj == Value; - case Operator.NotEqual: - return strObj != Value; - case Operator.StartsWith: - return strObj.StartsWith(Value); - case Operator.EndsWith: - return strObj.EndsWith(Value); - default: - throw new NotSupportedException("不支持的条件类型"); - } - } - return false; - } - } -} diff --git a/NodeFlow/Tool/SereinExpression/Resolver/ValueTypeConditionResolver.cs b/NodeFlow/Tool/SereinExpression/Resolver/ValueTypeConditionResolver.cs deleted file mode 100644 index f1cf7e1..0000000 --- a/NodeFlow/Tool/SereinExpression/Resolver/ValueTypeConditionResolver.cs +++ /dev/null @@ -1,128 +0,0 @@ -using Serein.Library.Utils; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Serein.NodeFlow.Tool.SereinExpression.Resolver -{ - public class ValueTypeConditionResolver : SereinConditionResolver where T : struct, IComparable - { - public enum Operator - { - /// - /// 不进行任何操作 - /// - Node, - /// - /// 大于 - /// - GreaterThan, - /// - /// 小于 - /// - LessThan, - /// - /// 等于 - /// - Equal, - /// - /// 大于或等于 - /// - GreaterThanOrEqual, - /// - /// 小于或等于 - /// - LessThanOrEqual, - /// - /// 在两者之间 - /// - InRange, - /// - /// 不在两者之间 - /// - OutOfRange - } - - public Operator Op { get; set; } - public T Value { get; set; } - public T RangeStart { get; set; } - public T RangeEnd { get; set; } - - public string ArithmeticExpression { get; set; } - - - public override bool Evaluate(object obj) - { - - var evaluatedValue = obj.ToConvert(); - if (!string.IsNullOrEmpty(ArithmeticExpression)) - { - evaluatedValue = SerinArithmeticExpressionEvaluator.Evaluate(ArithmeticExpression, evaluatedValue); - } - - switch (Op) - { - case Operator.GreaterThan: - return evaluatedValue.CompareTo(Value) > 0; - case Operator.LessThan: - return evaluatedValue.CompareTo(Value) < 0; - case Operator.Equal: - return evaluatedValue.CompareTo(Value) == 0; - case Operator.GreaterThanOrEqual: - return evaluatedValue.CompareTo(Value) >= 0; - case Operator.LessThanOrEqual: - return evaluatedValue.CompareTo(Value) <= 0; - case Operator.InRange: - return evaluatedValue.CompareTo(RangeStart) >= 0 && evaluatedValue.CompareTo(RangeEnd) <= 0; - case Operator.OutOfRange: - return evaluatedValue.CompareTo(RangeStart) < 0 || evaluatedValue.CompareTo(RangeEnd) > 0; - } - return false; - - //if (obj is T typedObj) - //{ - // numericValue = Convert.ToDouble(typedObj); - // numericValue = Convert.ToDouble(obj); - // if (!string.IsNullOrEmpty(ArithmeticExpression)) - // { - // numericValue = SerinArithmeticExpressionEvaluator.Evaluate(ArithmeticExpression, numericValue); - // } - - // T evaluatedValue = (T)Convert.ChangeType(numericValue, typeof(T)); - - // /*return Op switch - // { - // Operator.GreaterThan => evaluatedValue.CompareTo(Value) > 0, - // Operator.LessThan => evaluatedValue.CompareTo(Value) < 0, - // Operator.Equal => evaluatedValue.CompareTo(Value) == 0, - // Operator.GreaterThanOrEqual => evaluatedValue.CompareTo(Value) >= 0, - // Operator.LessThanOrEqual => evaluatedValue.CompareTo(Value) <= 0, - // Operator.InRange => evaluatedValue.CompareTo(RangeStart) >= 0 && evaluatedValue.CompareTo(RangeEnd) <= 0, - // Operator.OutOfRange => evaluatedValue.CompareTo(RangeStart) < 0 || evaluatedValue.CompareTo(RangeEnd) > 0, - // _ => throw new NotSupportedException("不支持的条件类型") - // };*/ - // switch (Op) - // { - // case Operator.GreaterThan: - // return evaluatedValue.CompareTo(Value) > 0; - // case Operator.LessThan: - // return evaluatedValue.CompareTo(Value) < 0; - // case Operator.Equal: - // return evaluatedValue.CompareTo(Value) == 0; - // case Operator.GreaterThanOrEqual: - // return evaluatedValue.CompareTo(Value) >= 0; - // case Operator.LessThanOrEqual: - // return evaluatedValue.CompareTo(Value) <= 0; - // case Operator.InRange: - // return evaluatedValue.CompareTo(RangeStart) >= 0 && evaluatedValue.CompareTo(RangeEnd) <= 0; - // case Operator.OutOfRange: - // return evaluatedValue.CompareTo(RangeStart) < 0 || evaluatedValue.CompareTo(RangeEnd) > 0; - // } - //} - //return false; - } - } - -} diff --git a/NodeFlow/Tool/SereinExpression/SereinConditionParser.cs b/NodeFlow/Tool/SereinExpression/SereinConditionParser.cs deleted file mode 100644 index bf6fe0a..0000000 --- a/NodeFlow/Tool/SereinExpression/SereinConditionParser.cs +++ /dev/null @@ -1,580 +0,0 @@ -using Newtonsoft.Json.Linq; -using Serein.Library.Utils; -using Serein.NodeFlow.Tool.SereinExpression.Resolver; -using System.ComponentModel.Design; -using System.Globalization; -using System.Reflection; - -namespace Serein.NodeFlow.Tool.SereinExpression -{ - - public class SereinConditionParser - { - public static bool To(T data, string expression) - { - try - { - if (string.IsNullOrEmpty(expression)) - { - return false; - } - var parse = ConditionParse(data, expression); - var result = parse.Evaluate(data); - return result; - - } - catch (Exception ex) - { - Console.WriteLine(ex); - throw; - } - } - - public static SereinConditionResolver ConditionParse(object? data, string expression) - { - if (expression.StartsWith('.')) // 表达式前缀属于从上一个节点数据对象获取成员值 - { - return ParseObjectExpression(data, expression); - } - else - { - return ParseSimpleExpression(data, expression); - } - - - //bool ContainsArithmeticOperators(string expression) - //{ - // return expression.Contains('+') || expression.Contains('-') || expression.Contains('*') || expression.Contains('/'); - //} - - } - - /// - /// 获取计算表达式的部分 - /// - /// - /// - private static string GetArithmeticExpression(string part) - { - int startIndex = part.IndexOf('['); - int endIndex = part.IndexOf(']'); - if (startIndex >= 0 && endIndex > startIndex) - { - return part.Substring(startIndex + 1, endIndex - startIndex - 1); - } - - return null; - - } - /// - /// 获取对象指定名称的成员 - /// - private static object? GetMemberValue(object? obj, string memberPath) - { - string[] members = memberPath[1..].Split('.'); - foreach (var member in members) - { - if (obj is null) return null; - Type type = obj.GetType(); - PropertyInfo? propertyInfo = type.GetProperty(member); - FieldInfo? fieldInfo = type.GetField(member); - if (propertyInfo != null) - obj = propertyInfo.GetValue(obj); - else if (fieldInfo != null) - obj = fieldInfo.GetValue(obj); - else - throw new ArgumentException($"Member {member} not found in type {type.FullName}"); - } - return obj; - } - - - /// - /// 解析对象表达式 - /// - private static SereinConditionResolver ParseObjectExpression(object? data, string expression) - { - var parts = expression.Split(' '); - string operatorStr = parts[0]; // 获取操作类型 - string valueStr; //= string.Join(' ', parts, 1, parts.Length - 1); - string memberPath; - Type type; - object? targetObj; - - // 尝试获取指定类型 - int typeStartIndex = expression.IndexOf('<'); - int typeEndIndex = expression.IndexOf('>'); - if (typeStartIndex + typeStartIndex == -2) - { - // 如果不需要转为指定类型 - memberPath = operatorStr; - targetObj = SerinExpressionEvaluator.Evaluate("@get " + operatorStr, data, out _); - //targetObj = GetMemberValue(data, operatorStr); - type = targetObj.GetType(); - operatorStr = parts[1].ToLower(); // - valueStr = string.Join(' ', parts.Skip(2)); - } - else - { - // 类型语法不正确 - if (typeStartIndex >= typeEndIndex) - { - throw new ArgumentException("无效的表达式格式"); - } - memberPath = expression.Substring(0, typeStartIndex).Trim(); - string typeStr = expression.Substring(typeStartIndex + 1, typeEndIndex - typeStartIndex - 1) - .Trim().ToLower(); // 手动置顶的类型 - - // 对象取值表达式 - parts = expression.Substring(typeEndIndex + 1).Trim().Split(' '); - if (parts.Length == 3) - { - operatorStr = parts[1].ToLower(); // 操作类型 - valueStr = string.Join(' ', parts.Skip(2)); // 表达式值 - } - else - { - operatorStr = parts[0].ToLower(); // 操作类型 - valueStr = string.Join(' ', parts.Skip(1)); // 表达式值 - } - Type? tempType = typeStr switch - { - "bool" => typeof(bool), - "float" => typeof(float), - "decimal" => typeof(decimal), - "double" => typeof(double), - "sbyte" => typeof(sbyte), - "byte" => typeof(byte), - "short" => typeof(short), - "ushort" => typeof(ushort), - "int" => typeof(int), - "uint" => typeof(uint), - "long" => typeof(long), - "ulong" => typeof(ulong), - "nint" => typeof(nint), - "nuint" => typeof(nuint), - "string" => typeof(string), - _ => Type.GetType(typeStr), - }; - type = tempType ?? throw new ArgumentException("对象表达式无效的类型声明"); - if (string.IsNullOrWhiteSpace(memberPath)) - { - targetObj = Convert.ChangeType(data, type); - } - else - { - targetObj = GetMemberValue(data, memberPath);// 获取对象成员,作为表达式的目标对象 - } - - } - - #region 解析类型 int - if (type.IsValueType) - { - //return GetValueResolver(type, valueStr, operatorStr, parts); - } - if (type == typeof(int)) - { - var op = ParseValueTypeOperator(operatorStr); - if (op == ValueTypeConditionResolver.Operator.InRange || op == ValueTypeConditionResolver.Operator.OutOfRange) - { - var temp = valueStr.Split('-'); - if (temp.Length < 2) - throw new ArgumentException($"范围无效:{valueStr}。"); - int rangeStart = int.Parse(temp[0], CultureInfo.InvariantCulture); - int rangeEnd = int.Parse(temp[1], CultureInfo.InvariantCulture); - return new MemberConditionResolver - { - Op = op, - RangeStart = rangeStart, - RangeEnd = rangeEnd, - TargetObj = targetObj, - ArithmeticExpression = GetArithmeticExpression(parts[0]), - }; - } - else - { - - int value = int.Parse(valueStr, CultureInfo.InvariantCulture); - - - return new MemberConditionResolver - { - TargetObj = targetObj, - //MemberPath = memberPath, - Op = ParseValueTypeOperator(operatorStr), - Value = value, - ArithmeticExpression = GetArithmeticExpression(parts[0]) - }; - - - } - } - #endregion - #region 解析类型 double - else if (type == typeof(double)) - { - double value = double.Parse(valueStr, CultureInfo.InvariantCulture); - return new MemberConditionResolver - { - //MemberPath = memberPath, - TargetObj = targetObj, - Op = ParseValueTypeOperator(operatorStr), - Value = value, - ArithmeticExpression = GetArithmeticExpression(parts[0]) - }; - - } - #endregion - #region 解析类型 bool - else if (type == typeof(bool)) - { - return new MemberConditionResolver - { - //MemberPath = memberPath, - TargetObj = targetObj, - Op = (ValueTypeConditionResolver.Operator)ParseBoolOperator(operatorStr) - }; - } - #endregion - #region 解析类型 string - else if (type == typeof(string)) - { - return new MemberStringConditionResolver - { - MemberPath = memberPath, - Op = ParseStringOperator(operatorStr), - Value = valueStr - }; - } - #endregion - - throw new NotSupportedException($"Type {type} is not supported."); - } - - - /// - /// 条件表达式解析 - /// - /// - /// - /// - /// - /// - private static SereinConditionResolver ParseSimpleExpression(object data, string expression) - { - if ("pass".Equals(expression.ToLower())) - { - return new PassConditionResolver - { - Op = PassConditionResolver.Operator.Pass, - }; - } - else - { - if ("not pass".Equals(expression.ToLower())) - { - return new PassConditionResolver - { - Op = PassConditionResolver.Operator.NotPass, - }; - } - if ("!pass".Equals(expression.ToLower())) - { - return new PassConditionResolver - { - Op = PassConditionResolver.Operator.NotPass, - }; - } - } - - - var parts = expression.Split(' '); - - if (parts.Length < 2) - throw new ArgumentException("无效的表达式格式。"); - - string operatorStr; - string valueStr; - Type type; - // 尝试获取指定类型 - int typeStartIndex = expression.IndexOf('<'); - int typeEndIndex = expression.IndexOf('>'); - if (typeStartIndex + typeStartIndex == -2) - { - // 如果不需要转为指定类型 - operatorStr = parts[0]; - valueStr = string.Join(' ', parts, 1, parts.Length - 1); - type = data.GetType(); - } - else - {//string typeStr = parts[0]; - string typeStr = expression.Substring(typeStartIndex + 1, typeEndIndex - typeStartIndex - 1) - .Trim().ToLower(); // 手动置顶的类型 - parts = expression.Substring(typeEndIndex + 1).Trim().Split(' '); - operatorStr = parts[0].ToLower(); // 操作类型 - valueStr = string.Join(' ', parts.Skip(1)); // 表达式值 - - - type = typeStr switch - { - "bool" => typeof(bool), - "float" => typeof(float), - "decimal" => typeof(decimal), - "double" => typeof(double), - "sbyte" => typeof(sbyte), - "byte" => typeof(byte), - "short" => typeof(short), - "ushort" => typeof(ushort), - "int" => typeof(int), - "uint" => typeof(uint), - "long" => typeof(long), - "ulong" => typeof(ulong), - "nint" => typeof(nint), - "nuint" => typeof(nuint), - _ => typeof(string), - }; - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if (type == typeof(bool)) - { - bool value = bool.Parse(valueStr); - return new BoolConditionResolver - { - Op = ParseBoolOperator(operatorStr), - Value = value, - }; - } - else if (type.IsValueType) - { - return GetValueResolver(type, valueStr, operatorStr, parts); - } - else if (type == typeof(string)) - { - return new StringConditionResolver - { - Op = ParseStringOperator(operatorStr), - Value = valueStr - }; - } - - throw new NotSupportedException($"Type {type} is not supported."); - } - - public static SereinConditionResolver GetValueResolver(Type valueType, string valueStr, string operatorStr, string[] parts)// where T : struct, IComparable - { - SereinConditionResolver resolver = valueType switch - { - Type t when t == typeof(float) => GetValueResolver(valueStr, operatorStr, parts), - Type t when t == typeof(decimal) => GetValueResolver(valueStr, operatorStr, parts), - Type t when t == typeof(double) => GetValueResolver(valueStr, operatorStr, parts), - Type t when t == typeof(sbyte) => GetValueResolver(valueStr, operatorStr, parts), - Type t when t == typeof(byte) => GetValueResolver(valueStr, operatorStr, parts), - Type t when t == typeof(short) => GetValueResolver(valueStr, operatorStr, parts), - Type t when t == typeof(ushort) => GetValueResolver(valueStr, operatorStr, parts), - Type t when t == typeof(int) => GetValueResolver(valueStr, operatorStr, parts), - Type t when t == typeof(uint) => GetValueResolver(valueStr, operatorStr, parts), - Type t when t == typeof(long) => GetValueResolver(valueStr, operatorStr, parts), - Type t when t == typeof(ulong) => GetValueResolver(valueStr, operatorStr, parts), - Type t when t == typeof(nint) => GetValueResolver(valueStr, operatorStr, parts), - Type t when t == typeof(nuint) => GetValueResolver(valueStr, operatorStr, parts), - _ => throw new ArgumentException("非预期值类型") - }; - return resolver; - } - - - private static ValueTypeConditionResolver GetValueResolver(string valueStr, string operatorStr, string[] parts) - where T :struct, IComparable - { - var op = ParseValueTypeOperator(operatorStr); - if (op == ValueTypeConditionResolver.Operator.InRange || op == ValueTypeConditionResolver.Operator.OutOfRange) - { - var temp = valueStr.Split('-'); - var leftNum = string.Empty; - var rightNum = string.Empty; - if (temp.Length < 2 || temp.Length > 4) - { - throw new ArgumentException($"范围无效:{valueStr}。"); - } - else if (temp.Length == 2) - { - leftNum = temp[0]; - rightNum = temp[1]; - } - else if (temp.Length == 3) - { - if (string.IsNullOrEmpty(temp[0]) - && !string.IsNullOrEmpty(temp[1]) - && !string.IsNullOrEmpty(temp[2])) - { - leftNum = "-" + temp[1]; - rightNum = temp[2]; - } - else - { - throw new ArgumentException($"范围无效:{valueStr}。"); - } - } - else if (temp.Length == 4) - { - if (string.IsNullOrEmpty(temp[0]) - && !string.IsNullOrEmpty(temp[1]) - && string.IsNullOrEmpty(temp[2]) - && !string.IsNullOrEmpty(temp[3])) - { - leftNum = "-" + temp[1]; - rightNum = temp[3]; - } - else - { - throw new ArgumentException($"范围无效:{valueStr}。"); - } - } - - - - return new ValueTypeConditionResolver - { - Op = op, - RangeStart = leftNum.ToValueData(), - RangeEnd = rightNum.ToValueData(), - ArithmeticExpression = GetArithmeticExpression(parts[0]), - }; - } - else - { - return new ValueTypeConditionResolver - { - Op = op, - Value = valueStr.ToValueData(), - ArithmeticExpression = GetArithmeticExpression(parts[0]) - }; - - } - } - //public static T ValueParse(object value) where T : struct, IComparable - //{ - // return (T)ValueParse(typeof(T), value); - //} - - //public static object ValueParse(Type type, object value) - //{ - - // string? valueStr = value.ToString(); - // if (string.IsNullOrEmpty(valueStr)) - // { - // throw new ArgumentException("value is null"); - // } - // object result = type switch - // { - // Type t when t.IsEnum => Enum.Parse(type, valueStr), - // Type t when t == typeof(bool) => bool.Parse(valueStr), - // Type t when t == typeof(float) => float.Parse(valueStr, CultureInfo.InvariantCulture), - // Type t when t == typeof(decimal) => decimal.Parse(valueStr, CultureInfo.InvariantCulture), - // Type t when t == typeof(double) => double.Parse(valueStr, CultureInfo.InvariantCulture), - // Type t when t == typeof(sbyte) => sbyte.Parse(valueStr, CultureInfo.InvariantCulture), - // Type t when t == typeof(byte) => byte.Parse(valueStr, CultureInfo.InvariantCulture), - // Type t when t == typeof(short) => short.Parse(valueStr, CultureInfo.InvariantCulture), - // Type t when t == typeof(ushort) => ushort.Parse(valueStr, CultureInfo.InvariantCulture), - // Type t when t == typeof(int) => int.Parse(valueStr, CultureInfo.InvariantCulture), - // Type t when t == typeof(uint) => uint.Parse(valueStr, CultureInfo.InvariantCulture), - // Type t when t == typeof(long) => long.Parse(valueStr, CultureInfo.InvariantCulture), - // Type t when t == typeof(ulong) => ulong.Parse(valueStr, CultureInfo.InvariantCulture), - // Type t when t == typeof(nint) => nint.Parse(valueStr, CultureInfo.InvariantCulture), - // Type t when t == typeof(nuint) => nuint.Parse(valueStr, CultureInfo.InvariantCulture), - // _ => throw new ArgumentException("非预期值类型") - // }; - // return result; - //} - - - - /// - /// 数值操作类型 - /// - /// - /// - /// - /// - private static ValueTypeConditionResolver.Operator ParseValueTypeOperator(string operatorStr) where T : struct, IComparable - { - return operatorStr switch - { - ">" => ValueTypeConditionResolver.Operator.GreaterThan, - "<" => ValueTypeConditionResolver.Operator.LessThan, - "==" => ValueTypeConditionResolver.Operator.Equal, - ">=" or "≥" => ValueTypeConditionResolver.Operator.GreaterThanOrEqual, - "<=" or "≤" => ValueTypeConditionResolver.Operator.LessThanOrEqual, - "in" => ValueTypeConditionResolver.Operator.InRange, - "!in" => ValueTypeConditionResolver.Operator.OutOfRange, - _ => throw new ArgumentException($"Invalid operator {operatorStr} for value type.") - }; - } - - /// - /// 布尔操作类型 - /// - /// - /// - /// - private static BoolConditionResolver.Operator ParseBoolOperator(string operatorStr) - { - return operatorStr switch - { - "is" or "==" or "equals" => BoolConditionResolver.Operator.Is, - _ => throw new ArgumentException($"Invalid operator {operatorStr} for bool type.") - }; - } - - /// - /// 字符串操作类型 - /// - /// - /// - /// - private static StringConditionResolver.Operator ParseStringOperator(string operatorStr) - { - return operatorStr.ToLower() switch - { - "c" or "contains" => StringConditionResolver.Operator.Contains, - "nc" or "doesnotcontain" => StringConditionResolver.Operator.DoesNotContain, - "sw" or "startswith" => StringConditionResolver.Operator.StartsWith, - "ew" or "endswith" => StringConditionResolver.Operator.EndsWith, - - "==" or "equals" => StringConditionResolver.Operator.Equal, - "!=" or "notequals" => StringConditionResolver.Operator.NotEqual, - - _ => throw new ArgumentException($"Invalid operator {operatorStr} for string type.") - }; - } - - } -} diff --git a/NodeFlow/Tool/SereinExpression/SereinConditionResolver.cs b/NodeFlow/Tool/SereinExpression/SereinConditionResolver.cs deleted file mode 100644 index e0ac6be..0000000 --- a/NodeFlow/Tool/SereinExpression/SereinConditionResolver.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Reflection; - -namespace Serein.NodeFlow.Tool.SereinExpression -{ - /// - /// 条件解析抽象类 - /// - public abstract class SereinConditionResolver - { - public abstract bool Evaluate(object obj); - } -} diff --git a/NodeFlow/Tool/SereinExpression/SerinExpressionEvaluator.cs b/NodeFlow/Tool/SereinExpression/SerinExpressionEvaluator.cs deleted file mode 100644 index b813e41..0000000 --- a/NodeFlow/Tool/SereinExpression/SerinExpressionEvaluator.cs +++ /dev/null @@ -1,361 +0,0 @@ -using Serein.Library.Utils; -using System.Data; - -namespace Serein.NodeFlow.Tool.SereinExpression -{ - /// - /// 使用表达式操作/获取 对象的值 - /// 获取值 @get .xx.xxx - /// 设置值 @set .xx.xxx = [data] - /// - /// 操作的对象 - /// - public class SerinArithmeticExpressionEvaluator where T : struct, IComparable - { - private static readonly DataTable table = new DataTable(); - - public static T Evaluate(string expression, T inputValue) - { - - // 替换占位符@为输入值 - expression = expression.Replace("@", inputValue.ToString()); - try - { - // 使用 DataTable.Compute 方法计算表达式 - var result = table.Compute(expression, string.Empty); - return (T)result; - } - catch - { - throw new ArgumentException("Invalid arithmetic expression."); - } - } - } - - public class SerinExpressionEvaluator - { - /// - /// - /// - /// 表达式 - /// 操作对象 - /// 是否改变了对象(Set语法) - /// - /// - /// - public static object? Evaluate(string expression, object targetObJ, out bool isChange) - { - var parts = expression.Split([' '], 2); - if (parts.Length != 2) - { - throw new ArgumentException("Invalid expression format."); - } - - var operation = parts[0].ToLower(); - var operand = parts[1][0] == '.' ? parts[1][1..] : parts[1]; - - var result = operation switch - { - "@num" => ComputedNumber(targetObJ, operand), - "@call" => InvokeMethod(targetObJ, operand), - "@get" => GetMember(targetObJ, operand), - "@set" => SetMember(targetObJ, operand), - _ => throw new NotSupportedException($"Operation {operation} is not supported.") - }; - - isChange = operation switch - { - /*"@num" => true, - "@call" => true, - "@get" => true,*/ - "@set" => false, - _ => true, - }; - - return result; - } - - - private static readonly char[] separator = ['(', ')']; - private static readonly char[] separatorArray = [',']; - - /// - /// 调用目标方法 - /// - /// 目标实例 - /// 方法名称 - /// - /// - private static object? InvokeMethod(object? target, string methodCall) - { - if (target is null) return null; - var methodParts = methodCall.Split(separator, StringSplitOptions.RemoveEmptyEntries); - if (methodParts.Length != 2) - { - throw new ArgumentException("Invalid method call format."); - } - - var methodName = methodParts[0]; - var parameterList = methodParts[1]; - var parameters = parameterList.Split(separatorArray, StringSplitOptions.RemoveEmptyEntries) - .Select(p => p.Trim()) - .ToArray(); - - var method = target.GetType().GetMethod(methodName) ?? throw new ArgumentException($"Method {methodName} not found on target."); - var parameterValues = method.GetParameters() - .Select((p, index) => Convert.ChangeType(parameters[index], p.ParameterType)) - .ToArray(); - - - return method.Invoke(target, parameterValues); - - } - /// - /// 获取值 - /// - /// 目标实例 - /// 属性路径 - /// - /// - private static object? GetMember(object? target, string memberPath) - { - if (target is null) return null; - // 分割成员路径,按 '.' 处理多级访问 - var members = memberPath.Split('.'); - - foreach (var member in members) - { - // 检查成员是否包含数组索引,例如 "cars[0]" - var arrayIndexStart = member.IndexOf('['); - if (arrayIndexStart != -1) - { - // 解析数组/集合名与索引部分 - var arrayName = member.Substring(0, arrayIndexStart); - var arrayIndexEnd = member.IndexOf(']'); - if (arrayIndexEnd == -1 || arrayIndexEnd <= arrayIndexStart + 1) - { - throw new ArgumentException($"Invalid array syntax for member {member}"); - } - - // 提取数组索引 - var indexStr = member.Substring(arrayIndexStart + 1, arrayIndexEnd - arrayIndexStart - 1); - if (!int.TryParse(indexStr, out int index)) - { - throw new ArgumentException($"Invalid array index '{indexStr}' for member {member}"); - } - - // 获取数组或集合对象 - var arrayProperty = target?.GetType().GetProperty(arrayName); - if (arrayProperty is null) - { - var arrayField = target?.GetType().GetField(arrayName); - if (arrayField is null) - { - throw new ArgumentException($"Member {arrayName} not found on target."); - } - else - { - target = arrayField.GetValue(target); - } - } - else - { - target = arrayProperty.GetValue(target); - } - - // 访问数组或集合中的指定索引 - if (target is Array array) - { - if (index < 0 || index >= array.Length) - { - throw new ArgumentException($"Index {index} out of bounds for array {arrayName}"); - } - target = array.GetValue(index); - } - else if (target is IList list) - { - if (index < 0 || index >= list.Count) - { - throw new ArgumentException($"Index {index} out of bounds for list {arrayName}"); - } - target = list[index]; - } - else - { - throw new ArgumentException($"Member {arrayName} is not an array or list."); - } - } - else - { - // 处理非数组情况的属性或字段 - var property = target?.GetType().GetProperty(member); - if (property is null) - { - var field = target?.GetType().GetField(member); - if (field is null) - { - throw new ArgumentException($"Member {member} not found on target."); - } - else - { - target = field.GetValue(target); - } - } - else - { - target = property.GetValue(target); - } - } - } - return target; - } - - /// - /// 设置目标的值 - /// - /// 目标实例 - /// 属性路径 - /// - /// - private static object? SetMember(object? target, string assignment) - { - var parts = assignment.Split(new[] { '=' }, 2); - if (parts.Length != 2) - { - throw new ArgumentException("Invalid assignment format."); - } - - var memberPath = parts[0].Trim(); - var value = parts[1].Trim(); - - var members = memberPath.Split('.'); - for (int i = 0; i < members.Length - 1; i++) - { - var member = members[i]; - - // 检查是否包含数组索引 - var arrayIndexStart = member.IndexOf('['); - if (arrayIndexStart != -1) - { - // 解析数组名和索引 - var arrayName = member.Substring(0, arrayIndexStart); - var arrayIndexEnd = member.IndexOf(']'); - if (arrayIndexEnd == -1 || arrayIndexEnd <= arrayIndexStart + 1) - { - throw new ArgumentException($"Invalid array syntax for member {member}"); - } - - var indexStr = member.Substring(arrayIndexStart + 1, arrayIndexEnd - arrayIndexStart - 1); - if (!int.TryParse(indexStr, out int index)) - { - throw new ArgumentException($"Invalid array index '{indexStr}' for member {member}"); - } - - // 获取数组或集合 - var arrayProperty = target?.GetType().GetProperty(arrayName); - if (arrayProperty is null) - { - var arrayField = target?.GetType().GetField(arrayName); - if (arrayField is null) - { - throw new ArgumentException($"Member {arrayName} not found on target."); - } - else - { - target = arrayField.GetValue(target); - } - - } - else - { - target = arrayProperty.GetValue(target); - } - - // 获取目标数组或集合中的指定元素 - if (target is Array array) - { - if (index < 0 || index >= array.Length) - { - throw new ArgumentException($"Index {index} out of bounds for array {arrayName}"); - } - target = array.GetValue(index); - } - else if (target is IList list) - { - if (index < 0 || index >= list.Count) - { - throw new ArgumentException($"Index {index} out of bounds for list {arrayName}"); - } - target = list[index]; - } - else - { - throw new ArgumentException($"Member {arrayName} is not an array or list."); - } - } - else - { - // 处理非数组情况的属性或字段 - var property = target?.GetType().GetProperty(member); - if (property is null) - { - var field = target?.GetType().GetField(member); - if (field is null) - { - throw new ArgumentException($"Member {member} not found on target."); - } - else - { - target = field.GetValue(target); - } - } - else - { - target = property.GetValue(target); - } - } - } - - // 设置值 - var lastMember = members.Last(); - - var lastProperty = target?.GetType().GetProperty(lastMember); - if (lastProperty is null) - { - var lastField = target?.GetType().GetField(lastMember); - if (lastField is null) - { - throw new ArgumentException($"Member {lastMember} not found on target."); - } - else - { - var convertedValue = Convert.ChangeType(value, lastField.FieldType); - lastField.SetValue(target, convertedValue); - } - } - else - { - var convertedValue = Convert.ChangeType(value, lastProperty.PropertyType); - lastProperty.SetValue(target, convertedValue); - } - - return target; - } - /// - /// 计算数学简单表达式 - /// - /// - /// - /// - private static decimal ComputedNumber(object value, string expression) - { - return ComputedNumber(value, expression); - } - - private static T ComputedNumber(object value, string expression) where T : struct, IComparable - { - T result = value.ToConvert(); - return SerinArithmeticExpressionEvaluator.Evaluate(expression, result); - } - } -} diff --git a/SereinFlow.sln b/SereinFlow.sln index 2ff6fb1..3f5dcfd 100644 --- a/SereinFlow.sln +++ b/SereinFlow.sln @@ -24,8 +24,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serein.FlowStartTool", "Flo EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serein.Library.NodeGenerator", "Serein.Library.MyGenerator\Serein.Library.NodeGenerator.csproj", "{5F7DE0B2-A5D3-492D-AC6C-F0C39EBEF365}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Serein.BaseNode", "Serein.BaseNode\Serein.BaseNode.csproj", "{9E7CEECB-EC9F-4D5F-8A04-49865B6DEC99}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -64,10 +62,6 @@ Global {5F7DE0B2-A5D3-492D-AC6C-F0C39EBEF365}.Debug|Any CPU.Build.0 = Debug|Any CPU {5F7DE0B2-A5D3-492D-AC6C-F0C39EBEF365}.Release|Any CPU.ActiveCfg = Release|Any CPU {5F7DE0B2-A5D3-492D-AC6C-F0C39EBEF365}.Release|Any CPU.Build.0 = Release|Any CPU - {9E7CEECB-EC9F-4D5F-8A04-49865B6DEC99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9E7CEECB-EC9F-4D5F-8A04-49865B6DEC99}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9E7CEECB-EC9F-4D5F-8A04-49865B6DEC99}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9E7CEECB-EC9F-4D5F-8A04-49865B6DEC99}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/WorkBench/MainWindow.xaml b/WorkBench/MainWindow.xaml index 7427049..7b0d6e4 100644 --- a/WorkBench/MainWindow.xaml +++ b/WorkBench/MainWindow.xaml @@ -94,7 +94,7 @@ - + diff --git a/WorkBench/Node/View/ActionRegionControl.xaml b/WorkBench/Node/View/ActionRegionControl.xaml deleted file mode 100644 index bc1862c..0000000 --- a/WorkBench/Node/View/ActionRegionControl.xaml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - diff --git a/WorkBench/Node/View/ActionRegionControl.xaml.cs b/WorkBench/Node/View/ActionRegionControl.xaml.cs deleted file mode 100644 index a71e5c2..0000000 --- a/WorkBench/Node/View/ActionRegionControl.xaml.cs +++ /dev/null @@ -1,128 +0,0 @@ -using Serein.Library; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Input; - -namespace Serein.Workbench.Node.View -{ - /// - /// ActionRegion.xaml 的交互逻辑 - /// - public partial class ActionRegionControl : NodeControlBase - { - private Point _dragStartPoint; - - //private new readonly CompositeActionNode Node; - - //public override NodeControlViewModel ViewModel { get ; set ; } - - public ActionRegionControl() : base(null) - { - InitializeComponent(); - } - //public ActionRegionControl(CompositeActionNode node) - //{ - // InitializeComponent(); - // //ViewModel = new NodeControlViewModel(node); - // DataContext = ViewModel; - // base.Name = "动作组合节点"; - //} - - public void AddAction(NodeControlBase node, bool isTask = false) - { - /*TextBlock actionText = new TextBlock - { - Text = node.MethodDetails.MethodName + (isTask ? " (Task)" : ""), - Margin = new Thickness(10, 2, 0, 0), - Tag = node.MethodDetails, - };*/ - /// Node?.AddNode((SingleActionNode)node.ViewModel.Node); - // ActionsListBox.Items.Add(node); - } - - /* public async Task ExecuteActions(DynamicContext context) - { - foreach (TextBlock item in ActionsListBox.Items) - { - dynamic tag = item.Tag; - IAction action = tag.Action; - bool isTask = tag.IsTask; - - if (isTask) - { - await Task.Run(() => action.Execute(Node.MethodDetails, context)); - } - else - { - action.Execute(Node.MethodDetails, context); - } - } - }*/ - - - - private void ActionsListBox_Drop(object sender, DragEventArgs e) - { - /*if (e.Data.GetDataPresent("Type")) - { - Type droppedType = e.Data.GetData("Type") as Type; - - if (droppedType != null && typeof(ICondition).IsAssignableFrom(droppedType) && droppedType.IsClass) - { - // 创建一个新的 TextBlock 并设置其属性 - TextBlock conditionText = new TextBlock - { - Text = droppedType.Name, - Margin = new Thickness(10, 2, 0, 0), - Tag = droppedType - }; - - // 为 TextBlock 添加鼠标左键按下事件处理程序 - // conditionText.MouseLeftButtonDown += TypeText_MouseLeftButtonDown; - // 为 TextBlock 添加鼠标移动事件处理程序 - // conditionText.MouseMove += TypeText_MouseMove; - - // 将 TextBlock 添加到 ActionsListBox 中 - ActionsListBox.Items.Add(conditionText); - } - }*/ - e.Handled = true; - } - - // 用于拖动的鼠标事件处理程序 - private void TypeText_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) - { - _dragStartPoint = e.GetPosition(null); - } - - private void TypeText_MouseMove(object sender, MouseEventArgs e) - { - Point mousePos = e.GetPosition(null); - Vector diff = _dragStartPoint - mousePos; - - if (e.LeftButton == MouseButtonState.Pressed && - (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance || - Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance)) - { - if (sender is TextBlock typeText) - { - MoveNodeData moveNodeData = new MoveNodeData - { - NodeControlType = Library.NodeControlType.ConditionRegion - }; - - // 创建一个 DataObject 用于拖拽操作,并设置拖拽效果 - DataObject dragData = new DataObject(MouseNodeType.CreateDllNodeInCanvas, moveNodeData); - - DragDrop.DoDragDrop(typeText, dragData, DragDropEffects.Move); - - - //var dragData = new DataObject(MouseNodeType.CreateNodeInCanvas, typeText.Tag); - //DragDrop.DoDragDrop(typeText, dragData, DragDropEffects.Move); - } - } - } - - - } -} diff --git a/WorkBench/Node/View/ConditionNodeControl.xaml b/WorkBench/Node/View/ConditionNodeControl.xaml index 9bbc7c9..73b59e2 100644 --- a/WorkBench/Node/View/ConditionNodeControl.xaml +++ b/WorkBench/Node/View/ConditionNodeControl.xaml @@ -26,7 +26,7 @@ - + @@ -44,8 +44,8 @@ - - + + @@ -83,12 +83,21 @@ - + + + + + + + + + + + + - - - + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WorkBench/Node/View/ExpOpNodeControl.xaml.cs b/WorkBench/Node/View/ExpOpNodeControl.xaml.cs index f564533..7525618 100644 --- a/WorkBench/Node/View/ExpOpNodeControl.xaml.cs +++ b/WorkBench/Node/View/ExpOpNodeControl.xaml.cs @@ -6,7 +6,7 @@ namespace Serein.Workbench.Node.View /// /// ExprOpNodeControl.xaml 的交互逻辑 /// - public partial class ExpOpNodeControl : NodeControlBase + public partial class ExpOpNodeControl : NodeControlBase, INodeJunction { public ExpOpNodeControl() : base() { @@ -20,5 +20,37 @@ namespace Serein.Workbench.Node.View DataContext = viewModel; InitializeComponent(); } + + /// + /// 入参控制点(可能有,可能没) + /// + JunctionControlBase INodeJunction.ExecuteJunction => this.ExecuteJunctionControl; + + /// + /// 下一个调用方法控制点(可能有,可能没) + /// + JunctionControlBase INodeJunction.NextStepJunction => this.NextStepJunctionControl; + + /// + /// 返回值控制点(可能有,可能没) + /// + JunctionControlBase INodeJunction.ReturnDataJunction => this.ResultJunctionControl; + + /// + /// 方法入参控制点(可能有,可能没) + /// + private JunctionControlBase[] argDataJunction; + /// + /// 方法入参控制点(可能有,可能没) + /// + JunctionControlBase[] INodeJunction.ArgDataJunction + { + get + { + argDataJunction = new JunctionControlBase[1]; + argDataJunction[0] = this.ArgJunctionControl; + return argDataJunction; + } + } } } diff --git a/WorkBench/Themes/Condition/BoolConditionControl.xaml b/WorkBench/Themes/Condition/BoolConditionControl.xaml deleted file mode 100644 index 54f1da1..0000000 --- a/WorkBench/Themes/Condition/BoolConditionControl.xaml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - diff --git a/WorkBench/Themes/Condition/BoolConditionControl.xaml.cs b/WorkBench/Themes/Condition/BoolConditionControl.xaml.cs deleted file mode 100644 index bb24e80..0000000 --- a/WorkBench/Themes/Condition/BoolConditionControl.xaml.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; - -namespace DynamicDemo.Themes.Condition -{ - /// - /// BoolConditionControl.xaml 的交互逻辑 - /// - public partial class BoolConditionControl : UserControl - { - public BoolConditionControl() - { - InitializeComponent(); - } - } -} diff --git a/WorkBench/Themes/Condition/IntConditionControl.xaml b/WorkBench/Themes/Condition/IntConditionControl.xaml deleted file mode 100644 index fd63f5c..0000000 --- a/WorkBench/Themes/Condition/IntConditionControl.xaml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - diff --git a/WorkBench/Themes/Condition/IntConditionControl.xaml.cs b/WorkBench/Themes/Condition/IntConditionControl.xaml.cs deleted file mode 100644 index c54439e..0000000 --- a/WorkBench/Themes/Condition/IntConditionControl.xaml.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; - -namespace DynamicDemo.Themes.Condition -{ - /// - /// IntConditionControl.xaml 的交互逻辑 - /// - public partial class IntConditionControl : UserControl - { - public IntConditionControl() - { - InitializeComponent(); - } - } -} diff --git a/WorkBench/Themes/Condition/Model.cs b/WorkBench/Themes/Condition/Model.cs deleted file mode 100644 index f4cbc01..0000000 --- a/WorkBench/Themes/Condition/Model.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace DynamicDemo.Themes.Condition -{ - //public class IntConditionNode : ConditionNode - //{ - // public int Value { get; set; } - // public int MinValue { get; set; } - // public int MaxValue { get; set; } - // public List ExcludeValues { get; set; } - - // public override bool Evaluate(object value) - // { - // if (value is int intValue) - // { - // switch (Condition) - // { - // case ConditionType.GreaterThan: - // return intValue > Value; - // case ConditionType.LessThan: - // return intValue < Value; - // case ConditionType.EqualTo: - // return intValue == Value; - // case ConditionType.Between: - // return intValue >= MinValue && intValue <= MaxValue; - // case ConditionType.NotBetween: - // return intValue < MinValue || intValue > MaxValue; - // case ConditionType.NotInRange: - // return !ExcludeValues.Contains(intValue); - // default: - // return false; - // } - // } - // return false; - // } - //} - - //public class BoolConditionNode : ConditionNode - //{ - // public override bool Evaluate(object value) - // { - // if (value is bool boolValue) - // { - // switch (Condition) - // { - // case ConditionType.IsTrue: - // return boolValue; - // case ConditionType.IsFalse: - // return !boolValue; - // default: - // return false; - // } - // } - // return false; - // } - //} - - - //public class StringConditionNode : ConditionNode - //{ - // public string Substring { get; set; } - - // public override bool Evaluate(object value) - // { - // if (value is string stringValue) - // { - // switch (Condition) - // { - // case ConditionType.Contains: - // return stringValue.Contains(Substring); - // case ConditionType.DoesNotContain: - // return !stringValue.Contains(Substring); - // case ConditionType.IsNotEmpty: - // return !string.IsNullOrEmpty(stringValue); - // default: - // return false; - // } - // } - // return false; - // } - //} - - -} diff --git a/WorkBench/Themes/Condition/StringConditionControl.xaml b/WorkBench/Themes/Condition/StringConditionControl.xaml deleted file mode 100644 index 457c286..0000000 --- a/WorkBench/Themes/Condition/StringConditionControl.xaml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - diff --git a/WorkBench/Themes/Condition/StringConditionControl.xaml.cs b/WorkBench/Themes/Condition/StringConditionControl.xaml.cs deleted file mode 100644 index 625532f..0000000 --- a/WorkBench/Themes/Condition/StringConditionControl.xaml.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; - -namespace DynamicDemo.Themes.Condition -{ - /// - /// StringConditionControl.xaml 的交互逻辑 - /// - public partial class StringConditionControl : UserControl - { - public StringConditionControl() - { - InitializeComponent(); - } - } -} diff --git a/WorkBench/Themes/ConditionControl.xaml b/WorkBench/Themes/ConditionControl.xaml deleted file mode 100644 index b542ca3..0000000 --- a/WorkBench/Themes/ConditionControl.xaml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - -