mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-02 15:50:47 +08:00
从DLL导入方法将按照方法名称首字母开始排序;规范化方法参数描述中的输入类型,改为枚举。
This commit is contained in:
14
Library/Enums/ParameterValueInputType.cs
Normal file
14
Library/Enums/ParameterValueInputType.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library
|
||||
{
|
||||
public enum ParameterValueInputType
|
||||
{
|
||||
Input,
|
||||
Select,
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,7 @@ namespace Serein.Library
|
||||
pd.DataType = null;
|
||||
pd.Name = null;
|
||||
pd.ArgDataSourceNodeGuid = null;
|
||||
pd.ExplicitTypeName = null;
|
||||
pd.InputType = ParameterValueInputType.Input;
|
||||
}
|
||||
this.MethodDetails.ParameterDetailss = null;
|
||||
this.MethodDetails.ActingInstance = null;
|
||||
|
||||
@@ -10,6 +10,8 @@ using System.Threading.Tasks;
|
||||
namespace Serein.Library
|
||||
{
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 节点入参参数详情
|
||||
/// </summary>
|
||||
@@ -57,7 +59,7 @@ namespace Serein.Library
|
||||
/// <para>Value :除以上类型之外的任意参数</para>
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
private string _explicitTypeName ;
|
||||
private ParameterValueInputType _inputType ;
|
||||
|
||||
/// <summary>
|
||||
/// 入参数据来源。默认使用上一节点作为入参数据。
|
||||
@@ -91,7 +93,7 @@ namespace Serein.Library
|
||||
private string _dataValue;
|
||||
|
||||
/// <summary>
|
||||
/// 只有当ExplicitTypeName 为 Select 时,才会需要该成员。
|
||||
/// 只有当 InputType 为 Select 时,才会需要该成员。
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true)]
|
||||
private string[] _items ;
|
||||
@@ -104,6 +106,8 @@ namespace Serein.Library
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public partial class ParameterDetails
|
||||
{
|
||||
|
||||
@@ -133,7 +137,7 @@ namespace Serein.Library
|
||||
Name = info.Name;
|
||||
DataType = Type.GetType(info.DataTypeFullName);
|
||||
ExplicitType = Type.GetType(info.ExplicitTypeFullName);
|
||||
ExplicitTypeName = info.ExplicitTypeName;
|
||||
InputType = info.InputType.ConvertEnum<ParameterValueInputType>();
|
||||
Items = info.Items;
|
||||
IsParams = info.IsParams;
|
||||
}
|
||||
@@ -151,7 +155,7 @@ namespace Serein.Library
|
||||
DataTypeFullName = this.DataType.FullName,
|
||||
Name = this.Name,
|
||||
ExplicitTypeFullName = this.ExplicitType.FullName,
|
||||
ExplicitTypeName = this.ExplicitTypeName,
|
||||
InputType = this.InputType.ToString(),
|
||||
Items = this.Items.Select(it => it).ToArray(),
|
||||
};
|
||||
}
|
||||
@@ -168,7 +172,7 @@ namespace Serein.Library
|
||||
Index = this.Index,
|
||||
IsExplicitData = this.IsExplicitData,
|
||||
ExplicitType = this.ExplicitType,
|
||||
ExplicitTypeName = this.ExplicitTypeName,
|
||||
InputType = this.InputType,
|
||||
//Convertor = this.Convertor,
|
||||
DataType = this.DataType,
|
||||
Name = this.Name,
|
||||
@@ -199,6 +203,11 @@ namespace Serein.Library
|
||||
{
|
||||
return context;
|
||||
}
|
||||
// 返回流程上下文
|
||||
if (typeof(NodeModelBase).IsAssignableFrom(DataType))
|
||||
{
|
||||
return NodeModel;
|
||||
}
|
||||
// 显式设置的参数
|
||||
if (IsExplicitData && !DataValue.StartsWith("@", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace Serein.Library
|
||||
/// <para>Bool : 布尔类型</para>
|
||||
/// <para>Value : 除以上类型之外的任意参数</para>
|
||||
/// </summary>
|
||||
public string ExplicitTypeName { get; set; }
|
||||
public string InputType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 参数选择器
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace Serein.NodeFlow.Model
|
||||
ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData,
|
||||
NodeModel = this,
|
||||
//Convertor = null,
|
||||
ExplicitTypeName = "Value",
|
||||
InputType = ParameterValueInputType.Input,
|
||||
Items = null,
|
||||
};
|
||||
this.MethodDetails.ParameterDetailss = [..pd];
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace Serein.NodeFlow.Model
|
||||
ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData,
|
||||
NodeModel = this,
|
||||
//Convertor = null,
|
||||
ExplicitTypeName = "Value",
|
||||
InputType = ParameterValueInputType.Input,
|
||||
Items = null,
|
||||
};
|
||||
this.MethodDetails.ParameterDetailss = [.. pd];
|
||||
|
||||
@@ -89,7 +89,7 @@ namespace Serein.NodeFlow.Model
|
||||
ArgDataSourceNodeGuid = string.Empty,
|
||||
ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData,
|
||||
NodeModel = this,
|
||||
ExplicitTypeName = "Value",
|
||||
InputType = ParameterValueInputType.Input,
|
||||
Items = null,
|
||||
IsParams = true,
|
||||
};
|
||||
|
||||
@@ -5,13 +5,21 @@ using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
|
||||
namespace Serein.NodeFlow
|
||||
{
|
||||
public class LibraryMdDd (MethodDetails methodDetails,DelegateDetails delegateDetails)
|
||||
{
|
||||
public MethodDetails MethodDetails { get; } = methodDetails;
|
||||
public DelegateDetails DelegateDetails { get; } = delegateDetails;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 加载在流程中的程序集依赖
|
||||
@@ -111,7 +119,7 @@ namespace Serein.NodeFlow
|
||||
var loaderExceptions = ex.LoaderExceptions;
|
||||
foreach (var loaderException in loaderExceptions)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.ERROR, loaderException.Message);
|
||||
SereinEnv.WriteLine(InfoType.ERROR, loaderException?.Message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -149,7 +157,7 @@ namespace Serein.NodeFlow
|
||||
// 从 scanTypes.Type 创建的方法信息
|
||||
// Md : 方法描述
|
||||
// Dd :方法对应的Emit委托
|
||||
List<(MethodDetails Md, DelegateDetails Dd)> detailss = new List<(MethodDetails Md, DelegateDetails Dd)>();
|
||||
List<LibraryMdDd> detailss = new List<LibraryMdDd>();
|
||||
|
||||
// 遍历扫描的类型
|
||||
foreach ((var type, var flowName) in scanTypes)
|
||||
@@ -165,7 +173,7 @@ namespace Serein.NodeFlow
|
||||
continue;
|
||||
}
|
||||
md.MethodAnotherName = flowName + md.MethodAnotherName; // 方法别名
|
||||
detailss.Add((md, dd));
|
||||
detailss.Add(new LibraryMdDd(md, dd));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,11 +184,26 @@ namespace Serein.NodeFlow
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#region 加载成功,缓存所有方法、委托的信息
|
||||
foreach ((var md, var dd) in detailss)
|
||||
// 简单排序一下
|
||||
//detailss = detailss.OrderBy(k => k.MethodDetails.MethodName,).ToList();
|
||||
|
||||
|
||||
|
||||
detailss.Sort((a, b) => string.Compare(a.MethodDetails.MethodName, b.MethodDetails.MethodName, StringComparison.OrdinalIgnoreCase));
|
||||
foreach (var item in detailss)
|
||||
{
|
||||
MethodDetailss.TryAdd(md.MethodName, md);
|
||||
DelegateDetailss.TryAdd(md.MethodName, dd);
|
||||
SereinEnv.WriteLine(InfoType.INFO, "loading method : " + item.MethodDetails.MethodName);
|
||||
|
||||
}
|
||||
|
||||
//detailss.Sort((a, b) => string.Compare());
|
||||
|
||||
#region 加载成功,缓存所有方法、委托的信息
|
||||
foreach (var item in detailss)
|
||||
{
|
||||
var key = item.MethodDetails.MethodName;
|
||||
MethodDetailss.TryAdd(key, item.MethodDetails);
|
||||
DelegateDetailss.TryAdd(key, item.DelegateDetails);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -229,7 +229,8 @@ namespace Serein.NodeFlow.Tool
|
||||
GC.WaitForPendingFinalizers();
|
||||
};
|
||||
var assembly = flowAlc.LoadFromAssemblyPath(dllFilePath); // 加载指定路径的程序集
|
||||
return LoadAssembly(assembly, actionUnload);
|
||||
var assembly_result = LoadAssembly(assembly, actionUnload);
|
||||
return assembly_result;
|
||||
}
|
||||
|
||||
/* var dir = Path.GetDirectoryName(dllFilePath); // 获取目录路径
|
||||
@@ -272,15 +273,26 @@ namespace Serein.NodeFlow.Tool
|
||||
}
|
||||
|
||||
FlowLibrary flowLibrary = new FlowLibrary(assembly, actionUnload);
|
||||
if (flowLibrary.LoadAssembly(assembly))
|
||||
var loadResult = flowLibrary.LoadAssembly(assembly); // 加载程序集
|
||||
if (loadResult)
|
||||
{
|
||||
_myFlowLibrarys.TryAdd(assembly.GetName().Name, flowLibrary);
|
||||
(NodeLibraryInfo, List<MethodDetailsInfo>) result = (flowLibrary.ToInfo(),
|
||||
flowLibrary.MethodDetailss.Values.Select(md => md.ToInfo()).ToList());
|
||||
var assemblyName = assembly.GetName().Name;
|
||||
if (string.IsNullOrEmpty(assemblyName))
|
||||
{
|
||||
actionUnload.Invoke();
|
||||
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败,没有程序集名称");
|
||||
}
|
||||
_myFlowLibrarys.TryAdd(assemblyName, flowLibrary);
|
||||
|
||||
List<MethodDetailsInfo> mdInfos = flowLibrary.MethodDetailss.Values.Select(md => md.ToInfo()).ToList();
|
||||
mdInfos.Sort((a, b) => string.Compare(a.MethodName, b.MethodName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
(NodeLibraryInfo, List<MethodDetailsInfo>) result = (flowLibrary.ToInfo(), mdInfos);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
actionUnload.Invoke();
|
||||
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Reflection;
|
||||
using Serein.Library.FlowNode;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Serein.NodeFlow.Tool;
|
||||
|
||||
@@ -47,13 +48,10 @@ public static class NodeMethodDetailsHelper
|
||||
}
|
||||
|
||||
var methodName = $"{assemblyName}.{type.Name}.{methodInfo.Name}";
|
||||
SereinEnv.WriteLine(InfoType.INFO, "loading method : " + methodName);
|
||||
|
||||
|
||||
// 创建参数信息
|
||||
var explicitDataOfParameters = GetExplicitDataOfParameters(methodInfo.GetParameters());
|
||||
|
||||
|
||||
|
||||
//// 通过表达式树生成委托
|
||||
//var methodDelegate = GenerateMethodDelegate(type, // 方法所在的对象类型
|
||||
// method, // 方法信息
|
||||
@@ -65,6 +63,34 @@ public static class NodeMethodDetailsHelper
|
||||
Type? returnType;
|
||||
bool isTask = IsGenericTask(methodInfo.ReturnType, out var taskResult);
|
||||
|
||||
|
||||
if (attribute.MethodDynamicType == Library.NodeType.UI)
|
||||
{
|
||||
if (isTask)
|
||||
{
|
||||
var innerType = methodInfo.ReturnType.GetGenericArguments()[0];
|
||||
if (innerType.IsGenericType && innerType != typeof(IEmbeddedContent))
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, $"[{methodName}]跳过创建,因为UI方法的返回值并非IEmbeddedContent,流程工作台将无法正确显示自定义控件界面以及传递数据。");
|
||||
methodDetails = null;
|
||||
delegateDetails = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (methodInfo.ReturnType != typeof(IEmbeddedContent))
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, $"[{methodName}]跳过创建,因为UI方法的返回值并非IEmbeddedContent,流程工作台将无法正确显示自定义控件界面以及传递数据。");
|
||||
methodDetails = null;
|
||||
delegateDetails = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 对于触发器
|
||||
if (attribute.MethodDynamicType == Library.NodeType.Flipflop)
|
||||
{
|
||||
if (methodInfo.ReturnType.IsGenericType && methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
|
||||
@@ -91,13 +117,8 @@ public static class NodeMethodDetailsHelper
|
||||
delegateDetails = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
//if (!isTask || taskResult != typeof(IFlipflopContext<object>))
|
||||
//{
|
||||
//
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
else if(isTask)
|
||||
{
|
||||
returnType = taskResult is null ? typeof(Task) : taskResult;
|
||||
@@ -111,8 +132,6 @@ public static class NodeMethodDetailsHelper
|
||||
attribute.AnotherName = methodInfo.Name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
var asyncPrefix = "[异步]"; // IsGenericTask(returnType) ? "[async]" : ;
|
||||
var methodMethodAnotherName = isTask ? asyncPrefix + attribute.AnotherName : attribute.AnotherName;
|
||||
|
||||
@@ -126,7 +145,7 @@ public static class NodeMethodDetailsHelper
|
||||
{
|
||||
ActingInstanceType = type,
|
||||
// ActingInstance = instance,
|
||||
MethodName = methodName,
|
||||
MethodName = NodeMethodDetailsHelper.GetMethodSignature(methodInfo),
|
||||
AssemblyName = assemblyName,
|
||||
MethodDynamicType = attribute.MethodDynamicType,
|
||||
MethodLockName = attribute.LockName,
|
||||
@@ -147,7 +166,17 @@ public static class NodeMethodDetailsHelper
|
||||
return true;
|
||||
|
||||
}
|
||||
public static string GetMethodSignature(MethodInfo method)
|
||||
{
|
||||
if (method == null) return string.Empty;
|
||||
|
||||
string methodName = method.Name;
|
||||
string returnType = method.ReturnType.Name;
|
||||
string parameters = string.Join(", ", method.GetParameters()
|
||||
.Select(p => $"{p.ParameterType.Name} {p.Name}"));
|
||||
|
||||
return $"{methodName}({parameters}) : {returnType}";
|
||||
}
|
||||
public static bool IsGenericTask(Type returnType, out Type? taskResult)
|
||||
{
|
||||
// 判断是否为 Task 类型或泛型 Task<T>
|
||||
@@ -236,6 +265,27 @@ public static class NodeMethodDetailsHelper
|
||||
#endregion
|
||||
}).ToArray();
|
||||
|
||||
foreach(var pd in tempParams)
|
||||
{
|
||||
var argType = pd.DataType;
|
||||
// 运行环境
|
||||
if (typeof(IFlowEnvironment).IsAssignableFrom(argType))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// 流程上下文
|
||||
if (typeof(IDynamicContext).IsAssignableFrom(argType))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// 节点模型
|
||||
if (typeof(NodeModelBase).IsAssignableFrom(argType))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
pd.IsExplicitData = true;
|
||||
|
||||
}
|
||||
|
||||
return tempParams;
|
||||
}
|
||||
@@ -260,14 +310,14 @@ public static class NodeMethodDetailsHelper
|
||||
dataType = parameterInfo.ParameterType;
|
||||
}
|
||||
|
||||
string explicitTypeName = GetExplicitTypeName(explicitParemType);
|
||||
var items = GetExplicitItems(explicitParemType, explicitTypeName);
|
||||
if ("Bool".Equals(explicitTypeName)) explicitTypeName = "Select"; // 布尔值 转为 可选类型
|
||||
var inputType = GetInputType(explicitParemType);
|
||||
var items = GetExplicitItems(explicitParemType, inputType);
|
||||
//if ("Bool".Equals(inputType)) inputType = "Select"; // 布尔值 转为 可选类型
|
||||
return new ParameterDetails
|
||||
{
|
||||
IsExplicitData = isExplicitData, //attribute is null ? parameterInfo.HasDefaultValue : true,
|
||||
Index = index, // 索引
|
||||
ExplicitTypeName = explicitTypeName, // Select/Bool/Value
|
||||
InputType = inputType, // Select/Bool/Value
|
||||
ExplicitType = explicitParemType,// 显示的入参类型
|
||||
//Convertor = func, // 转换器
|
||||
DataType = dataType, // 实际的入参类型
|
||||
@@ -286,17 +336,17 @@ public static class NodeMethodDetailsHelper
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
private static string GetExplicitTypeName(Type type)
|
||||
private static ParameterValueInputType GetInputType(Type type)
|
||||
{
|
||||
|
||||
return type switch
|
||||
{
|
||||
Type t when t.IsEnum => "Select",
|
||||
Type t when t == typeof(bool) => "Bool",
|
||||
Type t when t == typeof(string) => "Value",
|
||||
Type t when t == typeof(int) => "Value",
|
||||
Type t when t == typeof(double) => "Value",
|
||||
_ => "Value"
|
||||
Type t when t.IsEnum => ParameterValueInputType.Select,
|
||||
Type t when t == typeof(bool) => ParameterValueInputType.Select,
|
||||
Type t when t == typeof(string) => ParameterValueInputType.Input,
|
||||
Type t when t == typeof(int) => ParameterValueInputType.Input,
|
||||
Type t when t == typeof(double) => ParameterValueInputType.Input,
|
||||
_ => ParameterValueInputType.Input
|
||||
};
|
||||
}
|
||||
|
||||
@@ -305,14 +355,14 @@ public static class NodeMethodDetailsHelper
|
||||
/// 获取参数列表选项
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="explicitTypeName"></param>
|
||||
/// <param name="InputType"></param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<string> GetExplicitItems(Type type, string explicitTypeName)
|
||||
private static IEnumerable<string> GetExplicitItems(Type type, ParameterValueInputType InputType)
|
||||
{
|
||||
IEnumerable<string> items = explicitTypeName switch
|
||||
IEnumerable<string> items = InputType switch
|
||||
{
|
||||
"Select" => Enum.GetNames(type),
|
||||
"Bool" => ["True", "False"],
|
||||
ParameterValueInputType.Select when type == typeof(bool) => ["True", "False"],
|
||||
ParameterValueInputType.Select => Enum.GetNames(type),
|
||||
_ => []
|
||||
};
|
||||
return items;
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace Serein.Workbench.Avalonia.Converters
|
||||
|
||||
if(value is ParameterDetails pd)
|
||||
{
|
||||
|
||||
if (pd.ExplicitTypeName == "Value")
|
||||
|
||||
if (pd.InputType == ParameterValueInputType.Input)
|
||||
{
|
||||
|
||||
return false;
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Serein.Workbench.Avalonia.Custom.ViewModels
|
||||
return;
|
||||
}
|
||||
|
||||
if ("Value".Equals(ParameterDetails.ExplicitTypeName))
|
||||
if (ParameterDetails.InputType == ParameterValueInputType.Input )
|
||||
{
|
||||
// 值类型
|
||||
IsVisibleA = false;
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace Serein.Workbench.Node.View
|
||||
// 获取 MethodDetailsControl 实例
|
||||
var methodDetailsControl = this.MethodDetailsControl;
|
||||
var itemsControl = FindVisualChild<ItemsControl>(methodDetailsControl); // 查找 ItemsControl
|
||||
if (itemsControl != null)
|
||||
if (itemsControl != null && base.ViewModel.NodeModel.MethodDetails.ParameterDetailss != null)
|
||||
{
|
||||
var argDataJunction = new JunctionControlBase[base.ViewModel.NodeModel.MethodDetails.ParameterDetailss.Length];
|
||||
var controls = new List<JunctionControlBase>();
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsExplicitData}" Value="true" />
|
||||
<Condition Binding="{Binding ExplicitTypeName}" Value="Select" />
|
||||
<Condition Binding="{Binding InputType}" Value="Select" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="ContentTemplate">
|
||||
<Setter.Value>
|
||||
@@ -160,7 +160,7 @@
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsExplicitData}" Value="true" />
|
||||
<Condition Binding="{Binding ExplicitTypeName}" Value="Value" />
|
||||
<Condition Binding="{Binding InputType}" Value="Input" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="ContentTemplate">
|
||||
<Setter.Value>
|
||||
|
||||
Reference in New Issue
Block a user