using Serein.Library;
using Serein.Library.Utils;
using Serein.NodeFlow.Tool;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Serein.NodeFlow
{
///
/// 加载在流程中的程序集依赖
///
public class FlowLibrary
{
private readonly Assembly assembly;
private readonly Action actionOfUnloadAssmbly;
public FlowLibrary(Assembly assembly,
Action actionOfUnloadAssmbly)
{
this.assembly = assembly;
this.actionOfUnloadAssmbly = actionOfUnloadAssmbly;
}
public string FullName => assembly.GetName().FullName;
public string Version => assembly.GetName().Version.ToString();
///
/// 加载程序集时创建的方法描述
/// Key : 方法名称
/// Value :方法详情
///
public ConcurrentDictionary MethodDetailss { get; } = new ConcurrentDictionary();
///
/// 管理通过Emit动态构建的委托
/// Key :方法名称
/// Value :方法详情
///
public ConcurrentDictionary DelegateDetailss { get; } = new ConcurrentDictionary();
///
/// 记录不同的注册时机需要自动创建全局唯一实例的类型信息
///
public ConcurrentDictionary> RegisterTypes { get; } = new ConcurrentDictionary>();
///
/// 卸载当前程序集以及附带的所有信息
///
public void Upload()
{
DelegateDetailss.Clear();
RegisterTypes.Clear();
MethodDetailss.Clear();
actionOfUnloadAssmbly?.Invoke();
}
///
/// 转为依赖信息
///
///
public NodeLibraryInfo ToInfo()
{
return new NodeLibraryInfo
{
AssemblyName = assembly.GetName().Name,
FileName = Path.GetFileName(assembly.Location),
FilePath = assembly.Location,
};
}
///
/// 动态加载程序集
///
/// 程序集本身
///
public bool LoadAssembly(Assembly assembly)
{
#region 检查入参
// 加载DLL,创建 MethodDetails、实例作用对象、委托方法
var assemblyName = assembly.GetName().Name;
if (string.IsNullOrEmpty(assemblyName)) // 防止动态程序集没有定义程序集名称
{
return false;
}
List types;
try
{
types = assembly.GetTypes().ToList(); // 获取程序集中的所有类型
if (types.Count < 0) // 防止动态程序集中没有类型信息?
{
return false;
}
}
catch (ReflectionTypeLoadException ex)
{
// 获取加载失败的类型
var loaderExceptions = ex.LoaderExceptions;
foreach (var loaderException in loaderExceptions)
{
SereinEnv.WriteLine(InfoType.ERROR, loaderException.Message);
}
return false;
}
#endregion
#region 获取 DynamicFlow 特性的流程控制器,如果没有退出
// Type : 具有 DynamicFlowAttribute 标记的类型
// string : 类型元数据 DynamicFlowAttribute 特性中的 Name 属性 (用于生成方法描述时,添加在方法别名中提高可读性)
List<(Type Type, string Name)> scanTypes = new List<(Type Type, string Name)>();
// (Type, string)
// Type : 具有 DynamicFlowAttribute 标记的类型
// string : 类型元数据 DynamicFlowAttribute 特性中的 Name 属性
types = types.Where(type => type.GetCustomAttribute() is DynamicFlowAttribute dynamicFlowAttribute
&& dynamicFlowAttribute.Scan).ToList();
foreach (var type in types)
{
if (type.GetCustomAttribute() is DynamicFlowAttribute dynamicFlowAttribute)
{
scanTypes.Add((type, dynamicFlowAttribute.Name));
}
}
if (scanTypes.Count == 0)
{
// 类型没有流程控制器
return false;
}
#endregion
#region 创建对应的方法元数据
// 从 scanTypes.Type 创建的方法信息
// Md : 方法描述
// Dd :方法对应的Emit委托
List<(MethodDetails Md, DelegateDetails Dd)> detailss = new List<(MethodDetails Md, DelegateDetails Dd)>();
// 遍历扫描的类型
foreach ((var type, var flowName) in scanTypes)
{
var methodInfos = NodeMethodDetailsHelper.GetMethodsToProcess(type);
foreach (var methodInfo in methodInfos) // 遍历流程控制器类型中的方法信息
{
// 尝试创建
if (!NodeMethodDetailsHelper.TryCreateDetails(type, methodInfo, assemblyName,
out var md, out var dd)) // 返回的描述
{
SereinEnv.WriteLine(InfoType.ERROR, $"无法加载方法信息:{assemblyName}-{type}-{methodInfo}");
continue;
}
md.MethodAnotherName = flowName + md.MethodAnotherName; // 方法别名
detailss.Add((md, dd));
}
}
#endregion
#region 检查是否成功加载,如果成功,则真正写入到缓存的集合中
if (detailss.Count == 0)
{
return false;
}
#region 加载成功,缓存所有方法、委托的信息
foreach ((var md, var dd) in detailss)
{
MethodDetailss.TryAdd(md.MethodName, md);
DelegateDetailss.TryAdd(md.MethodName, dd);
}
#endregion
#region 加载成功,开始获取并记录所有需要自动实例化的类型(在流程启动时)
foreach (Type type in types)
{
if (type.GetCustomAttribute() is AutoRegisterAttribute attribute)
{
if (!RegisterTypes.TryGetValue(attribute.Class, out var valus))
{
valus = new List();
RegisterTypes.TryAdd(attribute.Class, valus);
}
valus.Add(type);
}
}
#endregion
#endregion
return true;
}
}
}