using Serein.Library.Api; using Serein.Library.Utils; using Serein.Library; using System.Collections.Concurrent; using System.Reflection; using Serein.Library.FlowNode; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.ComponentModel.DataAnnotations; using System.ComponentModel; namespace Serein.NodeFlow.Tool; public static class NodeMethodDetailsHelper { /// /// 获取处理方法 /// public static IEnumerable GetMethodsToProcess(Type type) { return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static) .Where(m => m.GetCustomAttribute()?.Scan == true); } /// /// 创建方法信息/委托信息 /// /// 方法所属的类型 /// 方法信息 /// 方法所属的程序集名称 /// 创建的方法描述,用来生成节点信息 /// 方法对应的Emit动态委托 /// 指示是否创建成功 public static bool TryCreateDetails(Type type, MethodInfo methodInfo, string assemblyName, [MaybeNullWhen(false)] out MethodInfo outMethodInfo, [MaybeNullWhen(false)] out MethodDetails methodDetails, [MaybeNullWhen(false)] out DelegateDetails delegateDetails) { var attribute = methodInfo.GetCustomAttribute(); if(attribute is null || attribute.Scan == false) { outMethodInfo = null; methodDetails = null; delegateDetails = null; return false; } var methodName = $"{assemblyName}.{type.Name}.{methodInfo.Name}"; // 创建参数信息 var explicitDataOfParameters = GetExplicitDataOfParameters(methodInfo.GetParameters()); //// 通过表达式树生成委托 //var methodDelegate = GenerateMethodDelegate(type, // 方法所在的对象类型 // method, // 方法信息 // method.GetParameters(),// 方法参数 // method.ReturnType);// 返回值 Type? returnType; bool isAsync = IsGenericTask(methodInfo.ReturnType, out var taskResult); if (attribute.MethodDynamicType == Library.NodeType.UI) { if (isAsync) { var innerType = methodInfo.ReturnType.GetGenericArguments()[0]; if (innerType.IsGenericType && innerType != typeof(IEmbeddedContent)) { SereinEnv.WriteLine(InfoType.WARN, $"[{methodName}]跳过创建,因为UI方法的返回值并非IEmbeddedContent,流程工作台将无法正确显示自定义控件界面以及传递数据。"); outMethodInfo = null; methodDetails = null; delegateDetails = null; return false; } } else { if (methodInfo.ReturnType != typeof(IEmbeddedContent)) { SereinEnv.WriteLine(InfoType.WARN, $"[{methodName}]跳过创建,因为UI方法的返回值并非IEmbeddedContent,流程工作台将无法正确显示自定义控件界面以及传递数据。"); outMethodInfo = null; methodDetails = null; delegateDetails = null; return false; } } } // 对于触发器 if (attribute.MethodDynamicType == Library.NodeType.Flipflop) { if (methodInfo.ReturnType.IsGenericType && methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) { // 获取 Task<> 的泛型参数类型 var innerType = methodInfo.ReturnType.GetGenericArguments()[0]; if (innerType.IsGenericType && innerType.GetGenericTypeDefinition() == typeof(IFlipflopContext<>)) { var flipflopType = innerType.GetGenericArguments()[0]; returnType = flipflopType; } else { SereinEnv.WriteLine(InfoType.WARN, $"[{methodName}]跳过创建,返回类型非预期的Task>。"); outMethodInfo = null; methodDetails = null; delegateDetails = null; return false; } } else { SereinEnv.WriteLine(InfoType.WARN, $"[{methodName}]跳过创建,因为触发器方法的返回值并非Task<>,将无法等待。"); outMethodInfo = null; methodDetails = null; delegateDetails = null; return false; } } else if(isAsync) { returnType = taskResult is null ? typeof(Task) : taskResult; } else { returnType = methodInfo.ReturnType; } if (string.IsNullOrEmpty(attribute.AnotherName)){ attribute.AnotherName = methodInfo.Name; } var asyncPrefix = "[异步]"; // IsGenericTask(returnType) ? "[async]" : ; var methodMethodAnotherName = isAsync ? asyncPrefix + attribute.AnotherName : attribute.AnotherName; bool hasParamsArg = false; if (explicitDataOfParameters.Length > 0) { hasParamsArg = explicitDataOfParameters[^1].IsParams; // 取最后一个参数描述,判断是否为params 入参 } var md = new MethodDetails() // 从DLL生成方法描述(元数据) { ActingInstanceType = type, // ActingInstance = instance, MethodName = NodeMethodDetailsHelper.GetMethodSignature(methodInfo), AssemblyName = assemblyName, MethodDynamicType = attribute.MethodDynamicType, MethodLockName = attribute.LockName, MethodAnotherName = methodMethodAnotherName, ParameterDetailss = explicitDataOfParameters, ReturnType = returnType, // 如果存在可变参数,取最后一个元素的下标,否则为-1; ParamsArgIndex = hasParamsArg ? explicitDataOfParameters.Length - 1 : -1, IsAsync = isAsync, }; //var emitMethodType = EmitHelper.CreateDynamicMethod(methodInfo, out var methodDelegate);// 返回值 var dd = new DelegateDetails(methodInfo) ; // 构造委托 outMethodInfo = methodInfo; methodDetails = md; delegateDetails = dd; 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})"; //return $"{methodName}({parameters}) : {returnType}"; } public static bool IsGenericTask(Type returnType, out Type? taskResult) { // 判断是否为 Task 类型或泛型 Task if (returnType == typeof(Task)) { taskResult = null; return true; } else if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>)) { // 获取泛型参数类型 Type genericArgument = returnType.GetGenericArguments()[0]; taskResult = genericArgument; return true; } else { taskResult = null; return false; } } private static ConcurrentDictionary ConvertorInstance =[]; /// /// 获取参数信息 /// /// /// private static ParameterDetails[] GetExplicitDataOfParameters(ParameterInfo[] parameters) { var tempParams = parameters.Select((it, index) => { Type paremType; #region 存在“枚举=>类型”转换器 if (it.GetCustomAttribute() is EnumTypeConvertorAttribute attribute1 && attribute1 is not null) { // 存在类型选择器 paremType = attribute1.EnumType; return GetExplicitDataOfParameter(it, index, paremType, true); // “枚举=>类型”转换器 获取参数 } #endregion #region 存在自定义的转换器 else if (it.GetCustomAttribute() is BindConvertorAttribute attribute2 && attribute2 is not null) { paremType = attribute2.EnumType; string key = typeof(IEnumConvertor<,>).FullName + attribute2.EnumType.FullName + attribute2.ConvertorType.FullName; if (!ConvertorInstance.ContainsKey(key)) { Type enumConvertorType = typeof(IEnumConvertor<,>); // 定义具体类型 Type specificType = enumConvertorType.MakeGenericType(attribute2.EnumType, it.ParameterType); // 获取实现类的类型 Type implementorType = attribute2.ConvertorType; // 创建实现类的实例 object instance = Activator.CreateInstance(implementorType); // 调用 Convert 方法 MethodInfo convertMethod = implementorType.GetMethod("Convertor"); ConvertorInstance[key] = (instance, convertMethod); } //object func(object enumValue) //{ // (var obj, var methodInfo) = ConvertorInstance[key]; // return methodInfo?.Invoke(obj, [enumValue]); //} // 确保实例实现了所需接口 ParameterDetails ed = GetExplicitDataOfParameter(it, index, paremType, true); // 自定义的转换器 获取参数 return ed; } #endregion #region 常规方法的获取参数 else { var tmp = GetExplicitDataOfParameter(it, index, it.ParameterType, it.HasDefaultValue); // 常规方法的获取参数 return tmp; } #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; } }*/ return tempParams; } private static ParameterDetails GetExplicitDataOfParameter(ParameterInfo parameterInfo, int index, Type explicitParemType, bool isExplicitData) { bool hasParams = parameterInfo.IsDefined(typeof(ParamArrayAttribute)); // 判断是否为可变参数 Type dataType; if (hasParams && parameterInfo.ParameterType.GetElementType() is Type paramsArgType) // 获取可变参数的子项类型 { // 可选参数为 Array 类型,所以需要获取子项类型 // 如果 hasParams 为 true ,说明一定存在可选参数,所以 paramsArgType 一定不为 null dataType = paramsArgType; explicitParemType = paramsArgType; } else { dataType = parameterInfo.ParameterType; } isExplicitData = true; string description = string.Empty; // 入参描述 var nodeParmsAttribute = parameterInfo.GetCustomAttribute(); if(nodeParmsAttribute is not null) { if (!parameterInfo.HasDefaultValue) { isExplicitData = nodeParmsAttribute.IsExplicit; // 设置是否是显式参数 } if (string.IsNullOrEmpty(nodeParmsAttribute.Name)) { description = nodeParmsAttribute.Name; // 设置显示的名称 } } else { description = parameterInfo.GetCustomAttribute()?.Description ?? string.Empty; // 判断是否存在注释特性 } 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, // 索引 InputType = inputType, // Select/Bool/Value ExplicitType = explicitParemType,// 显示的入参类型 //Convertor = func, // 转换器 DataType = dataType, // 实际的入参类型 Name = parameterInfo.Name, DataValue = parameterInfo.HasDefaultValue ? parameterInfo?.DefaultValue?.ToString() : "", // 如果存在默认值,则使用默认值 Items = items.ToArray(), // 如果是枚举值入参,则获取枚举类型的字面量 IsParams = hasParams, // 判断是否为可变参数 Description = description // 入参描述 }; } /// /// 判断使用输入器还是选择器 /// /// /// private static ParameterValueInputType GetInputType(Type type) { return type switch { 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 }; } /// /// 获取参数列表选项 /// /// /// /// private static IEnumerable GetExplicitItems(Type type, ParameterValueInputType InputType) { IEnumerable items = InputType switch { ParameterValueInputType.Select when type == typeof(bool) => ["True", "False"], ParameterValueInputType.Select => Enum.GetNames(type), _ => [] }; return items; } //private static Delegate GenerateMethodDelegate(Type type, MethodInfo methodInfo, ParameterInfo[] parameters, Type returnType) //{ // var parameterTypes = parameters.Select(p => p.ParameterType).ToArray(); // var parameterCount = parameters.Length; // if (returnType == typeof(void)) // { // if (parameterCount == 0) // { // // 无返回值,无参数 // return ExpressionHelper.MethodCaller(type, methodInfo); // } // else // { // // 无返回值,有参数 // return ExpressionHelper.MethodCaller(type, methodInfo, parameterTypes); // } // } // // else if (returnType == typeof(Task