mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-05-01 03:53:22 +08:00
表达式节点、条件表达式节点改用Serein.Script进行构造解析执行,避免了文本解析带来的性能损耗。
This commit is contained in:
@@ -50,15 +50,14 @@ namespace Serein.Library
|
|||||||
Flipflop,
|
Flipflop,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>动作节点,可以异步等待</para>
|
/// <para>动作节点,可以异步等待</para>
|
||||||
/// <para>如果不显式的设置入参数据(例如文本、@Get取值表达式),就会默认使用该节点的运行时上一个节点的数据。</para>
|
/// <para>如果不显式的设置入参数据,就会默认使用该节点的运行时上一个节点的数据。</para>
|
||||||
/// <para>假如上一节点是某个对象,但入参需要的是对象中某个属性/字段,则建议使用取值表达式、表达式节点获取所需要的数据。</para>
|
/// <para>假如上一节点是某个对象,但入参需要的是对象中某个属性/字段,则建议使用表达式节点获取所需要的数据。</para>
|
||||||
/// <para>关于@Get取值表达式的使用方法:</para>
|
/// <para>关于@Get取值表达式的使用方法:</para>
|
||||||
/// <para>public class UserInfo </para>
|
/// <para>public class UserInfo </para>
|
||||||
/// <para>{ </para>
|
/// <para>{ </para>
|
||||||
/// <para> public string Name; // 取值表达式:@Get .Name </para>
|
/// <para> public string Name; // 取值表达式:@Get .Name </para>
|
||||||
/// <para> public string[] PhoneNums; // 获取第1项的取值表达式:@Get .PhoneNums[0] </para>
|
/// <para> public string[] PhoneNums; // 取值表达式:@Get .PhoneNums </para>
|
||||||
/// <para> } </para>
|
/// <para> } </para>
|
||||||
/// <para>取值表达式可以符合直觉的如此获取实例成员:@Get .Data.Array[2].Data......</para>
|
|
||||||
/// <para>格式说明:@Get大小写不敏感,然后空一格,需要标记“.”,然后才是获取成员名称(成员名称大小写敏感)。</para>
|
/// <para>格式说明:@Get大小写不敏感,然后空一格,需要标记“.”,然后才是获取成员名称(成员名称大小写敏感)。</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Action,
|
Action,
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
using Serein.Library;
|
using Serein.Library.Utils;
|
||||||
using Serein.Library.Api;
|
|
||||||
using Serein.Library.Utils;
|
|
||||||
using Serein.Library.Utils.SereinExpression;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Dynamic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Serein.Library
|
namespace Serein.Library
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using Serein.Library.Utils.SereinExpression;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -119,10 +116,6 @@ namespace Serein.Library
|
|||||||
public partial class ParameterDetails
|
public partial class ParameterDetails
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用于创建元数据
|
/// 用于创建元数据
|
||||||
@@ -276,17 +269,8 @@ namespace Serein.Library
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. 表达式处理
|
|
||||||
if (IsExplicitData && DataValue.StartsWith("@", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
var lower = DataValue.ToLowerInvariant();
|
|
||||||
if (lower.StartsWith("@get") || lower.StartsWith("@dtc") || lower.StartsWith("@data"))
|
|
||||||
{
|
|
||||||
inputParameter = SerinExpressionEvaluator.Evaluate(DataValue, inputParameter, out _);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6. 类型转换
|
// 5. 类型转换
|
||||||
if (!DataType.IsValueType && inputParameter is null)
|
if (!DataType.IsValueType && inputParameter is null)
|
||||||
throw new Exception($"[arg{Index}] 参数不能为null");
|
throw new Exception($"[arg{Index}] 参数不能为null");
|
||||||
|
|
||||||
@@ -303,7 +287,10 @@ namespace Serein.Library
|
|||||||
throw new Exception($"[arg{Index}] 类型不匹配:目标类型为 {DataType},实际类型为 {actualType}");
|
throw new Exception($"[arg{Index}] 类型不匹配:目标类型为 {DataType},实际类型为 {actualType}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
|
|
||||||
|
|
||||||
|
/* /// <summary>
|
||||||
/// 转为方法入参数据
|
/// 转为方法入参数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
@@ -347,7 +334,7 @@ namespace Serein.Library
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*#region “枚举-类型”转换器
|
*//*#region “枚举-类型”转换器
|
||||||
if (ExplicitType is not null && ExplicitType.IsEnum && DataType != ExplicitType)
|
if (ExplicitType is not null && ExplicitType.IsEnum && DataType != ExplicitType)
|
||||||
{
|
{
|
||||||
var resultEnum = Enum.Parse(ExplicitType, DataValue);
|
var resultEnum = Enum.Parse(ExplicitType, DataValue);
|
||||||
@@ -359,7 +346,7 @@ namespace Serein.Library
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion*/
|
#endregion*//*
|
||||||
|
|
||||||
// 需要获取预入参数据
|
// 需要获取预入参数据
|
||||||
object inputParameter;
|
object inputParameter;
|
||||||
@@ -473,7 +460,7 @@ namespace Serein.Library
|
|||||||
|
|
||||||
throw new Exception($"[arg{Index}][{Name}][{DataType}]入参类型不符合,当前预入参类型为{inputParameterType}");
|
throw new Exception($"[arg{Index}][{Name}][{DataType}]入参类型不符合,当前预入参类型为{inputParameterType}");
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"[{this.Index}] {(string.IsNullOrWhiteSpace(this.Description) ? string.Empty : $"({this.Description})")}{this.Name} : {this.DataType?.FullName}";
|
return $"[{this.Index}] {(string.IsNullOrWhiteSpace(this.Description) ? string.Empty : $"({this.Description})")}{this.Name} : {this.DataType?.FullName}";
|
||||||
|
|||||||
@@ -42,12 +42,15 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Remove="Http\**" />
|
<Compile Remove="Http\**" />
|
||||||
<Compile Remove="Network\**" />
|
<Compile Remove="Network\**" />
|
||||||
|
<Compile Remove="Utils\SereinExpression\**" />
|
||||||
<Compile Remove="Utils\SerinExpression\**" />
|
<Compile Remove="Utils\SerinExpression\**" />
|
||||||
<EmbeddedResource Remove="Http\**" />
|
<EmbeddedResource Remove="Http\**" />
|
||||||
<EmbeddedResource Remove="Network\**" />
|
<EmbeddedResource Remove="Network\**" />
|
||||||
|
<EmbeddedResource Remove="Utils\SereinExpression\**" />
|
||||||
<EmbeddedResource Remove="Utils\SerinExpression\**" />
|
<EmbeddedResource Remove="Utils\SerinExpression\**" />
|
||||||
<None Remove="Http\**" />
|
<None Remove="Http\**" />
|
||||||
<None Remove="Network\**" />
|
<None Remove="Network\**" />
|
||||||
|
<None Remove="Utils\SereinExpression\**" />
|
||||||
<None Remove="Utils\SerinExpression\**" />
|
<None Remove="Utils\SerinExpression\**" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ namespace Serein.Library.Utils.SereinExpression
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 条件解析器(生成IL进行判断)
|
/// 条件解析器(生成IL进行判断)
|
||||||
/// 格式: data.[propertyName] [operator] [value]
|
/// 格式: data.[propertyName] [operator] [value]
|
||||||
|
/// 返回值:boolea
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SereinConditionParser
|
public class SereinConditionParser
|
||||||
{
|
{
|
||||||
@@ -113,11 +114,6 @@ namespace Serein.Library.Utils.SereinExpression
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//bool ContainsArithmeticOperators(string expression)
|
|
||||||
//{
|
|
||||||
// return expression.Contains('+') || expression.Contains('-') || expression.Contains('*') || expression.Contains('/');
|
|
||||||
//}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using Serein.Library.Utils.SereinExpression;
|
|
||||||
using Serein.NodeFlow.Model.Library;
|
|
||||||
using Serein.NodeFlow.Services;
|
using Serein.NodeFlow.Services;
|
||||||
using Serein.NodeFlow.Tool;
|
using Serein.NodeFlow.Tool;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -667,7 +665,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
// "NodeModel.Path"
|
// "NodeModel.Path"
|
||||||
if (TryGetNodeModel(nodeGuid, out var nodeModel))
|
if (TryGetNodeModel(nodeGuid, out var nodeModel))
|
||||||
{
|
{
|
||||||
SerinExpressionEvaluator.Evaluate($"@Set .{path} = {value}", nodeModel, out _); // 更改对应的数据
|
//SerinExpressionEvaluator.Evaluate($"@Set .{path} = {value}", nodeModel, out _); // 更改对应的数据
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
using Serein.Library.Utils;
|
using Serein.Script;
|
||||||
using Serein.Library.Utils.SereinExpression;
|
|
||||||
using System;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Dynamic;
|
using System.Dynamic;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
@@ -125,44 +122,41 @@ namespace Serein.NodeFlow.Model
|
|||||||
// 使用自动取参
|
// 使用自动取参
|
||||||
var pd = MethodDetails.ParameterDetailss[INDEX_EXPRESSION];
|
var pd = MethodDetails.ParameterDetailss[INDEX_EXPRESSION];
|
||||||
var hasNode = context.Env.TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var argSourceNode);
|
var hasNode = context.Env.TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var argSourceNode);
|
||||||
if (hasNode)
|
if (!hasNode)
|
||||||
{
|
{
|
||||||
context.NextOrientation = ConnectionInvokeType.IsError;
|
/*context.NextOrientation = ConnectionInvokeType.IsError;
|
||||||
return new FlowResult(this.Guid, context);
|
return new FlowResult(this.Guid, context);*/
|
||||||
}
|
parameter = null;
|
||||||
if (hasNode)
|
|
||||||
{
|
|
||||||
return new FlowResult(this.Guid, context);
|
|
||||||
}
|
|
||||||
if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
|
||||||
{
|
|
||||||
result = context.GetFlowData(argSourceNode.Guid).Value; // 使用自定义节点的参数
|
|
||||||
}
|
|
||||||
else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
|
||||||
{
|
|
||||||
CancellationTokenSource cts = new CancellationTokenSource();
|
|
||||||
var nodeResult = await argSourceNode.ExecutingAsync(context, cts.Token);
|
|
||||||
result = nodeResult.Value;
|
|
||||||
cts?.Cancel();
|
|
||||||
cts?.Dispose();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = context.TransmissionData(this.Guid).Value; // 条件节点透传上一节点的数据
|
if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
||||||
|
{
|
||||||
|
result = context.GetFlowData(argSourceNode.Guid).Value; // 使用自定义节点的参数
|
||||||
|
}
|
||||||
|
else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
||||||
|
{
|
||||||
|
CancellationTokenSource cts = new CancellationTokenSource();
|
||||||
|
var nodeResult = await argSourceNode.ExecutingAsync(context, cts.Token);
|
||||||
|
result = nodeResult.Value;
|
||||||
|
cts?.Cancel();
|
||||||
|
cts?.Dispose();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = context.TransmissionData(this.Guid).Value; // 条件节点透传上一节点的数据
|
||||||
|
}
|
||||||
|
parameter = result; // 使用上一节点的参数
|
||||||
}
|
}
|
||||||
parameter = result; // 使用上一节点的参数
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var exp = ExplicitData?.ToString();
|
var exp = ExplicitData?.ToString();
|
||||||
if (!string.IsNullOrEmpty(exp) && exp.StartsWith('@'))
|
if (!string.IsNullOrWhiteSpace(exp) && exp.StartsWith("@Get", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
parameter = result; // 表达式获取上一节点数据
|
parameter = GetValueExpressionAsync(context, result, exp);
|
||||||
if (parameter is not null)
|
|
||||||
{
|
|
||||||
parameter = SerinExpressionEvaluator.Evaluate(exp, parameter, out _);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -173,7 +167,8 @@ namespace Serein.NodeFlow.Model
|
|||||||
bool judgmentResult = false;
|
bool judgmentResult = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
judgmentResult = SereinConditionParser.To(parameter, Expression);
|
judgmentResult = await ConditionExpressionAsync(context, parameter, Expression);
|
||||||
|
//judgmentResult = SereinConditionParser.To(parameter, Expression);
|
||||||
context.NextOrientation = judgmentResult ? ConnectionInvokeType.IsSucceed : ConnectionInvokeType.IsFail;
|
context.NextOrientation = judgmentResult ? ConnectionInvokeType.IsSucceed : ConnectionInvokeType.IsFail;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -189,6 +184,95 @@ namespace Serein.NodeFlow.Model
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 解析取值表达式
|
||||||
|
/// </summary>
|
||||||
|
private SereinScript getValueScript;
|
||||||
|
private string getValueExpression;
|
||||||
|
private async Task<object?> GetValueExpressionAsync(IFlowContext flowContext, object? data, string expression)
|
||||||
|
{
|
||||||
|
var dataName = nameof(data);
|
||||||
|
if (!expression.Equals(getValueExpression))
|
||||||
|
{
|
||||||
|
getValueExpression = expression;
|
||||||
|
getValueScript = new SereinScript();
|
||||||
|
var dataType = data is null ? typeof(object) : data.GetType();
|
||||||
|
if (expression[0..4].Equals("@get", StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
expression = expression[4..];
|
||||||
|
// 表达式默认包含 “.”
|
||||||
|
expression = $"return {dataName}{expression};";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 表达式默认包含 “.”
|
||||||
|
expression = $"return {expression};";
|
||||||
|
}
|
||||||
|
var resultType = getValueScript.ParserScript(expression, new Dictionary<string, Type>
|
||||||
|
{
|
||||||
|
{ dataName, dataType},
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
IScriptInvokeContext scriptContext = new ScriptInvokeContext(flowContext);
|
||||||
|
scriptContext.SetVarValue(dataName, data);
|
||||||
|
|
||||||
|
var result = await getValueScript.InterpreterAsync(scriptContext);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 解析条件
|
||||||
|
/// </summary>
|
||||||
|
private SereinScript conditionScript;
|
||||||
|
private string conditionExpression;
|
||||||
|
|
||||||
|
private async Task<bool> ConditionExpressionAsync(IFlowContext flowContext, object? data, string expression)
|
||||||
|
{
|
||||||
|
var dataName = nameof(data);
|
||||||
|
if (!expression.Equals(conditionExpression))
|
||||||
|
{
|
||||||
|
conditionExpression = expression;
|
||||||
|
conditionScript = new SereinScript();
|
||||||
|
var dataType = data is null ? typeof(object) : data.GetType();
|
||||||
|
expression = expression.Trim();
|
||||||
|
if (expression[0] == '.')
|
||||||
|
{
|
||||||
|
// 对象取值
|
||||||
|
expression = $"return {dataName}{expression};";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 直接表达式
|
||||||
|
expression = $"return {dataName}{expression};";
|
||||||
|
}
|
||||||
|
_ = conditionScript.ParserScript(expression, new Dictionary<string, Type>
|
||||||
|
{
|
||||||
|
{ dataName, dataType},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
IScriptInvokeContext scriptContext = new ScriptInvokeContext(flowContext);
|
||||||
|
scriptContext.SetVarValue(dataName, data);
|
||||||
|
|
||||||
|
var result = await conditionScript.InterpreterAsync(scriptContext);
|
||||||
|
if(result is bool @bool)
|
||||||
|
{
|
||||||
|
return @bool;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flowContext.NextOrientation = ConnectionInvokeType.IsError;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
using Serein.Library.Utils.SereinExpression;
|
using Serein.Script;
|
||||||
using System.Dynamic;
|
using System.Dynamic;
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Model
|
namespace Serein.NodeFlow.Model
|
||||||
@@ -96,44 +96,40 @@ namespace Serein.NodeFlow.Model
|
|||||||
var pd = MethodDetails.ParameterDetailss[0];
|
var pd = MethodDetails.ParameterDetailss[0];
|
||||||
|
|
||||||
var hasNode = context.Env.TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var argSourceNode);
|
var hasNode = context.Env.TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var argSourceNode);
|
||||||
if (hasNode)
|
if (!hasNode)
|
||||||
{
|
{
|
||||||
context.NextOrientation = ConnectionInvokeType.IsError;
|
/*context.NextOrientation = ConnectionInvokeType.IsError;
|
||||||
return new FlowResult(this.Guid, context);
|
return new FlowResult(this.Guid, context);*/
|
||||||
|
parameter = null;
|
||||||
}
|
}
|
||||||
if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
else
|
||||||
{
|
{
|
||||||
// 使用自定义节点的参数
|
if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
||||||
parameter = context.GetFlowData(argSourceNode.Guid).Value;
|
{
|
||||||
}
|
// 使用自定义节点的参数
|
||||||
else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
parameter = context.GetFlowData(argSourceNode.Guid).Value;
|
||||||
{
|
}
|
||||||
// 立刻调用目标节点,然后使用其返回值
|
else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
||||||
var cts = new CancellationTokenSource();
|
{
|
||||||
var result = await argSourceNode.ExecutingAsync(context, cts.Token);
|
// 立刻调用目标节点,然后使用其返回值
|
||||||
cts?.Cancel();
|
var cts = new CancellationTokenSource();
|
||||||
cts?.Dispose();
|
var result = await argSourceNode.ExecutingAsync(context, cts.Token);
|
||||||
parameter = result.Value;
|
cts?.Cancel();
|
||||||
|
cts?.Dispose();
|
||||||
|
parameter = result.Value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 条件节点透传上一节点的数据
|
// 条件节点透传上一节点的数据
|
||||||
parameter = context.TransmissionData(this.Guid);
|
parameter = context.TransmissionData(this.Guid);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var newData = SerinExpressionEvaluator.Evaluate(Expression, parameter, out bool isChange);
|
var result = await GetValueExpressionAsync(context, parameter, Expression);
|
||||||
object? result = null;
|
|
||||||
if (isChange)
|
|
||||||
{
|
|
||||||
result = newData;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = parameter;
|
|
||||||
}
|
|
||||||
|
|
||||||
context.NextOrientation = ConnectionInvokeType.IsSucceed;
|
context.NextOrientation = ConnectionInvokeType.IsSucceed;
|
||||||
return new FlowResult(this.Guid, context, result);
|
return new FlowResult(this.Guid, context, result);
|
||||||
}
|
}
|
||||||
@@ -146,5 +142,45 @@ namespace Serein.NodeFlow.Model
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 解析取值表达式
|
||||||
|
/// </summary>
|
||||||
|
private SereinScript getValueScript;
|
||||||
|
private string getValueExpression;
|
||||||
|
private async Task<object?> GetValueExpressionAsync(IFlowContext flowContext, object? data, string expression)
|
||||||
|
{
|
||||||
|
var dataName = nameof(data);
|
||||||
|
if (!expression.Equals(getValueExpression))
|
||||||
|
{
|
||||||
|
getValueExpression = expression;
|
||||||
|
getValueScript = new SereinScript();
|
||||||
|
var dataType = data is null ? typeof(object) : data.GetType();
|
||||||
|
if (expression[0..4].Equals("@get", StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
expression = expression[4..];
|
||||||
|
// 表达式默认包含 “.”
|
||||||
|
expression = $"return {dataName}{expression};";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 表达式默认包含 “.”
|
||||||
|
expression = $"return {expression};";
|
||||||
|
}
|
||||||
|
var resultType = getValueScript .ParserScript(expression, new Dictionary<string, Type>
|
||||||
|
{
|
||||||
|
{ dataName, dataType},
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
IScriptInvokeContext scriptContext = new ScriptInvokeContext(flowContext);
|
||||||
|
scriptContext.SetVarValue(dataName, data);
|
||||||
|
|
||||||
|
var result = await getValueScript .InterpreterAsync(scriptContext);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,17 +108,12 @@ https://space.bilibili.com/33526379
|
|||||||
* 其它获取到全局数据的方式:
|
* 其它获取到全局数据的方式:
|
||||||
1. 表达式 :
|
1. 表达式 :
|
||||||
~~~
|
~~~
|
||||||
@Get #KeyName# // 使用##符号表达全局数据KeyName的标识符
|
@Get global("DataName") // 使用global表达全局数据 DataName 的标识符
|
||||||
~~~
|
~~~
|
||||||
2. Script代码:
|
2. Script代码:
|
||||||
~~~~
|
~~~~
|
||||||
data = global("YOUR-NAME"); // 获取全局数据节点中的数据
|
data = global("DataName"); // 获取全局数据节点中 DataName 的数据
|
||||||
~~~~
|
~~~~
|
||||||
3. C# 代码中(不建议):
|
|
||||||
~~~
|
|
||||||
SereinEnv.GetFlowGlobalData("KeyName"); // 获取全局数据
|
|
||||||
SereinEnv.AddOrUpdateFlowGlobalData("KeyName", obj); // 设置/更新全局数据,不建议
|
|
||||||
~~~
|
|
||||||
## 3. 从DLL生成控件的枚举值:
|
## 3. 从DLL生成控件的枚举值:
|
||||||
* **Action - 动作**
|
* **Action - 动作**
|
||||||
* 入参:自定义。如果入参类型为IFlowContext,会传入当前的上下文;如果入参类型为IFlowNode,会传入节点对应的实体Model。如果不显式指定参数来源,参数会尝试获取运行时上一节点返回值,并根据当前入参类型尝试进行类型转换。
|
* 入参:自定义。如果入参类型为IFlowContext,会传入当前的上下文;如果入参类型为IFlowNode,会传入节点对应的实体Model。如果不显式指定参数来源,参数会尝试获取运行时上一节点返回值,并根据当前入参类型尝试进行类型转换。
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Serein.Script
|
namespace Serein.Script
|
||||||
{
|
{
|
||||||
public class ScriptInvokeContext : IScriptInvokeContext
|
public sealed class ScriptInvokeContext : IScriptInvokeContext
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 脚本使用流程上下文
|
/// 脚本使用流程上下文
|
||||||
|
|||||||
@@ -1,27 +1,9 @@
|
|||||||
using Newtonsoft.Json.Linq;
|
using Serein.Library.Api;
|
||||||
using Serein.Library.Api;
|
|
||||||
using Serein.Library.Utils.SereinExpression;
|
|
||||||
using Serein.Workbench.Tool;
|
using Serein.Workbench.Tool;
|
||||||
using System;
|
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Markup.Primitives;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using System.Windows.Navigation;
|
|
||||||
using System.Windows.Shapes;
|
|
||||||
using System.Xml.Linq;
|
|
||||||
using static Serein.Workbench.Themes.TypeViewerWindow;
|
using static Serein.Workbench.Themes.TypeViewerWindow;
|
||||||
|
|
||||||
namespace Serein.Workbench.Themes
|
namespace Serein.Workbench.Themes
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
<nodeView:FlowCallNodeControl MaxWidth="110" MaxHeight="160" x:Name="FlowCallNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
|
<nodeView:FlowCallNodeControl MaxWidth="110" MaxHeight="160" x:Name="FlowCallNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
|
||||||
<nodeView:ScriptNodeControl MaxWidth="110" MaxHeight="160" x:Name="ScriptNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
|
<nodeView:ScriptNodeControl MaxWidth="110" MaxHeight="160" x:Name="ScriptNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
|
||||||
<nodeView:GlobalDataControl MaxWidth="110" MaxHeight="160" x:Name="GlobalDataControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
|
<nodeView:GlobalDataControl MaxWidth="110" MaxHeight="160" x:Name="GlobalDataControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
|
||||||
<!--<nodeView:ExpOpNodeControl MaxWidth="110" MaxHeight="160" x:Name="ExpOpNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>-->
|
<nodeView:ExpOpNodeControl MaxWidth="110" MaxHeight="160" x:Name="ExpOpNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
|
||||||
<!--<nodeView:ConditionNodeControl MaxWidth="110" MaxHeight="160" x:Name="ConditionNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>-->
|
<nodeView:ConditionNodeControl MaxWidth="110" MaxHeight="160" x:Name="ConditionNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
|
||||||
<!--<nodeView:ConditionRegionControl x:Name="ConditionRegionControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>-->
|
<!--<nodeView:ConditionRegionControl x:Name="ConditionRegionControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>-->
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|||||||
Reference in New Issue
Block a user