using Serein.Library;
using Serein.Library.Api;
using Serein.Library.Utils;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
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,
[NotNullWhen(true)] out MethodInfo? outMethodInfo,
[NotNullWhen(true)] out MethodDetails? methodDetails,
[NotNullWhen(true)] 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 = EmitHelper.IsGenericTask(methodInfo.ReturnType, out var taskResult);
bool isStatic = methodInfo.IsStatic;
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 innerTypes = methodInfo.ReturnType.GetGenericArguments();
if(innerTypes.Length == 1)
{
var innerType = innerTypes[0];
returnType = innerType;
}
else
{
SereinEnv.WriteLine(InfoType.WARN, $"[{methodName}]跳过创建,返回类型非预期的Task。");
outMethodInfo = null;
methodDetails = null;
delegateDetails = null;
return false;
}
//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,
IsStatic = isStatic,
};
//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}";
}
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 存在自定义的转换器
#if false
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;
}
#endif
#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