LocalFlowEnvironment文件丢失,需要重写

This commit is contained in:
fengjiayi
2025-06-22 21:53:37 +08:00
parent 999060b67a
commit 97df2a04b2
58 changed files with 4285 additions and 354 deletions

View File

@@ -260,8 +260,8 @@ namespace Serein.Library.Api
public NodeConnectChangeEventArgs(string canvasGuid,
string fromNodeGuid,
string toNodeGuid,
JunctionOfConnectionType junctionOfConnectionType, // 指示需要创建什么类型的连接线
int argIndex,
JunctionOfConnectionType junctionOfConnectionType, // 指示需要创建什么类型的连接线
ConnectionArgSourceType connectionArgSourceType, // 节点对应的方法入参所需参数来源
ConnectChangeType changeType) // 需要创建连接线还是删除连接线
{
@@ -296,15 +296,15 @@ namespace Serein.Library.Api
/// <summary>
/// 指示需要创建什么类型的连接线
/// </summary>
public JunctionOfConnectionType JunctionOfConnectionType { get;}
public JunctionOfConnectionType JunctionOfConnectionType { get; } = JunctionOfConnectionType.None;
/// <summary>
/// 节点对应的方法入参所需参数来源
/// </summary>
public ConnectionArgSourceType ConnectionArgSourceType { get;}
public ConnectionArgSourceType ConnectionArgSourceType { get;}
/// <summary>
/// 第几个参数
/// </summary>
public int ArgIndex { get;}
public int ArgIndex { get; } = -1;
}
@@ -814,7 +814,7 @@ namespace Serein.Library.Api
/// <summary>
/// 节点视图模型管理类
/// </summary>
NodeMVVMManagement NodeMVVMManagement { get; }
NodeMVVMService NodeMVVMManagement { get; }
#endregion
#region
@@ -904,23 +904,17 @@ namespace Serein.Library.Api
/// <param name="width">宽度</param>
/// <param name="height">高度</param>
/// <returns></returns>
Task<FlowCanvasDetailsInfo> CreateCanvasAsync(string canvasName, int width , int height);
void CreateCanvas(string canvasName, int width , int height);
/// <summary>
/// 删除画布
/// </summary>
/// <param name="canvasGuid">画布Guid</param>
/// <returns></returns>
Task<bool> RemoveCanvasAsync(string canvasGuid);
void RemoveCanvas(string canvasGuid);
/// <summary>
/// 设置流程起点节点
/// </summary>
/// <param name="canvasGuid">所在画布</param>
/// <param name="nodeGuid">尝试设置为起始节点的节点Guid</param>
/// <returns>被设置为起始节点的Guid</returns>
Task<string> SetStartNodeAsync(string canvasGuid, string nodeGuid);
/// <summary>
/// 在两个节点之间创建连接关系
@@ -931,7 +925,7 @@ namespace Serein.Library.Api
/// <param name="fromNodeJunctionType">起始节点控制点</param>
/// <param name="toNodeJunctionType">目标节点控制点</param>
/// <param name="invokeType">决定了方法执行后的后继行为</param>
Task<bool> ConnectInvokeNodeAsync(string canvasGuid,
void ConnectInvokeNode(string canvasGuid,
string fromNodeGuid,
string toNodeGuid,
JunctionType fromNodeJunctionType,
@@ -948,7 +942,7 @@ namespace Serein.Library.Api
/// <param name="toNodeJunctionType">目标节点控制点</param>
/// <param name="argSourceType">决定了方法参数来源</param>
/// <param name="argIndex">设置第几个参数</param>
Task<bool> ConnectArgSourceNodeAsync(string canvasGuid,
void ConnectArgSourceNode(string canvasGuid,
string fromNodeGuid,
string toNodeGuid,
JunctionType fromNodeJunctionType,
@@ -956,6 +950,23 @@ namespace Serein.Library.Api
ConnectionArgSourceType argSourceType,
int argIndex);
/// <summary>
/// 移除两个节点之间的方法调用关系
/// </summary>
/// <param name="canvasGuid">所在画布</param>
/// <param name="fromNodeGuid">起始节点</param>
/// <param name="toNodeGuid">目标节点</param>
/// <param name="connectionType">连接类型</param>
void RemoveInvokeConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType);
/// <summary>
/// 移除连接节点之间参数传递的关系
/// </summary>
/// <param name="canvasGuid">所在画布</param>
/// <param name="fromNodeGuid">起始节点Guid</param>
/// <param name="toNodeGuid">目标节点Guid</param>
/// <param name="argIndex">连接到第几个参数</param>
void RemoveArgSourceConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex);
/// <summary>
@@ -965,8 +976,14 @@ namespace Serein.Library.Api
/// <param name="nodeType">控件类型</param>
/// <param name="position">节点在画布上的位置(</param>
/// <param name="methodDetailsInfo">节点绑定的方法说明</param>
Task<NodeInfo> CreateNodeAsync(string canvasGuid, NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null);
void CreateNode(string canvasGuid, NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null);
/// <summary>
/// 移除节点
/// </summary>
/// <param name="canvasGuid">所在画布</param>
/// <param name="nodeGuid">待移除的节点Guid</param>
void RemoveNode(string canvasGuid, string nodeGuid);
/// <summary>
/// 将节点放置在容器中
@@ -975,15 +992,22 @@ namespace Serein.Library.Api
/// <param name="nodeGuid">需要放置的节点Guid</param>
/// <param name="containerNodeGuid">存放节点的容器Guid</param>
/// <returns></returns>
Task<bool> PlaceNodeToContainerAsync(string canvasGuid, string nodeGuid, string containerNodeGuid);
void PlaceNodeToContainer(string canvasGuid, string nodeGuid, string containerNodeGuid);
/// <summary>
/// 将节点放置在容器中
/// </summary>
/// <param name="canvasGuid">所在画布</param>
/// <param name="nodeGuid">需要取出的节点Guid</param>
Task<bool> TakeOutNodeToContainerAsync(string canvasGuid, string nodeGuid);
void TakeOutNodeToContainer(string canvasGuid, string nodeGuid);
/// <summary>
/// 设置流程起点节点
/// </summary>
/// <param name="canvasGuid">所在画布</param>
/// <param name="nodeGuid">尝试设置为起始节点的节点Guid</param>
/// <returns>被设置为起始节点的Guid</returns>
void SetStartNode(string canvasGuid, string nodeGuid);
/// <summary>
/// 设置两个节点某个类型的方法调用关系为优先调用
@@ -992,32 +1016,8 @@ namespace Serein.Library.Api
/// <param name="toNodeGuid">目标节点</param>
/// <param name="connectionType">连接关系</param>
/// <returns></returns>
Task<bool> SetConnectPriorityInvoke(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType);
void SetConnectPriorityInvoke(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType);
/// <summary>
/// 移除两个节点之间的方法调用关系
/// </summary>
/// <param name="canvasGuid">所在画布</param>
/// <param name="fromNodeGuid">起始节点</param>
/// <param name="toNodeGuid">目标节点</param>
/// <param name="connectionType">连接类型</param>
Task<bool> RemoveConnectInvokeAsync(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType);
/// <summary>
/// 移除连接节点之间参数传递的关系
/// </summary>
/// <param name="canvasGuid">所在画布</param>
/// <param name="fromNodeGuid">起始节点Guid</param>
/// <param name="toNodeGuid">目标节点Guid</param>
/// <param name="argIndex">连接到第几个参数</param>
Task<bool> RemoveConnectArgSourceAsync(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex);
/// <summary>
/// 移除节点/区域/基础控件
/// </summary>
/// <param name="canvasGuid">所在画布</param>
/// <param name="nodeGuid">待移除的节点Guid</param>
Task<bool> RemoveNodeAsync(string canvasGuid, string nodeGuid);
/// <summary>
/// 改变可选参数的数目
@@ -1026,8 +1026,7 @@ namespace Serein.Library.Api
/// <param name="isAdd">true增加参数false减少参数</param>
/// <param name="paramIndex">以哪个参数为模板进行拷贝,或删去某个参数(该参数必须为可选参数)</param>
/// <returns></returns>
Task<bool> ChangeParameter(string nodeGuid, bool isAdd, int paramIndex);
void ChangeParameter(string nodeGuid, bool isAdd, int paramIndex);
#endregion
@@ -1114,6 +1113,7 @@ namespace Serein.Library.Api
/// <para>需要你提供一个由你实现的ISereinIOC接口实现类</para>
/// <para>当你将流程运行环境集成在你的项目时,并希望流程运行时使用你提供的对象,而非自动创建</para>
/// <para>就需要你调用这个方法用来替换运行环境的IOC容器</para>
/// <para>注意,是流程运行时,而非运行环境</para>
/// </summary>
/// <param name="ioc"></param>
void UseExternalIOC(ISereinIOC ioc);

View File

@@ -72,14 +72,19 @@ namespace Serein.Library.Api
MethodDetails MethodDetails { get; set; }
/// <summary>
/// 父节点
/// 父节点集合
/// </summary>
Dictionary<ConnectionInvokeType, List<IFlowNode>> PreviousNodes { get;}
/// <summary>
/// 子节点
/// 子节点集合
/// </summary>
Dictionary<ConnectionInvokeType, List<IFlowNode>> SuccessorNodes { get; set; }
/// <summary>
/// 需要该节点返回结果作为入参参数的节点集合
/// </summary>
Dictionary<ConnectionArgSourceType, List<IFlowNode>> NeedResultNodes { get; }
/// <summary>
/// 当该节点放置在某个具有容器行为的节点时,该值指示其容器节点
/// </summary>
@@ -94,10 +99,10 @@ namespace Serein.Library.Api
/// 节点创建时的行为
/// </summary>
void OnCreating();
/// <summary>
/*/// <summary>
/// 节点移除时的行为
/// </summary>
void Remove();
void Remove();*/
/// <summary>
/// 节点保存时如若需要保存自定义数据,可通过该方法进行控制保存逻辑

View File

@@ -18,14 +18,14 @@ namespace Serein.Library.Api
ISereinIOC Reset();
/// <summary>
/// 通过指定类型的方式注册实例
/// 通过指定类型的方式注册实例,该类型的实例由你提供
/// </summary>
/// <param name="type">实例类型</param>
/// <returns></returns>
ISereinIOC Register(Type type);
/// <summary>
/// 通过指定类型的方式注册实例
/// 通过指定类型的方式注册实例该类型将由IOC容器自动创建
/// </summary>
/// <param name="type">实例类型</param>
/// <param name="getInstance">获取实例的回调函数</param>
@@ -33,14 +33,14 @@ namespace Serein.Library.Api
ISereinIOC Register(Type type, Func<object> getInstance);
/// <summary>
/// 通过泛型的方式注册实例
/// 通过泛型的方式注册类型该类型将由IOC容器自动创建
/// </summary>
/// <typeparam name="T">实例类型</typeparam>
/// <returns></returns>
ISereinIOC Register<T>();
/// <summary>
/// 通过泛型的方式注册实例
/// 通过泛型的方式注册类型,该类型的实例由你提供
/// </summary>
/// <typeparam name="T">实例类型</typeparam>
/// <param name="getInstance">获取实例的回调函数</param>
@@ -48,7 +48,7 @@ namespace Serein.Library.Api
ISereinIOC Register<T>(Func<T> getInstance);
/// <summary>
/// 注册接口的实例
/// 注册接口的实例,该接口类型的实现类实例由你提供
/// </summary>
/// <typeparam name="TService">接口类型</typeparam>
/// <typeparam name="TImplementation">实例类型</typeparam>
@@ -78,13 +78,21 @@ namespace Serein.Library.Api
/// <para>给定一个类型由IOC容器负责创建实例如果存在多个构造函数将由参数最多的构造函数开始尝试创建。</para>
/// <para></para>
/// </summary>
object CreateTempObject(Type type);
object CreateObject(Type type);
/// <summary>
/// <para>给定一个类型由IOC容器负责创建实例如果存在多个构造函数将由参数最多的构造函数开始尝试创建。</para>
/// <para></para>
/// </summary>
T CreateTempObject<T>();
T CreateObject<T>();
/// <summary>
/// 给定一个实例,尽可能地在该实例中具有[AutoInjection]特性的属性上设置为IOC容器中已有的对应类型的对象。
/// </summary>
/// <typeparam name="T">对应的类型</typeparam>
/// <param name="instance">传入的实例</param>
/// <returns></returns>
T InjectDependenciesProperty<T>(T instance);
/// <summary>
/// 搜寻已注册的类型生成依赖关系依次实例化并注入依赖项缓存在由IOC容器维护的Map中直到手动调用Reset()方法。

View File

@@ -103,51 +103,101 @@ namespace Serein.Library
/// 新增可变参数
/// </summary>
/// <param name="index"></param>
public bool AddParamsArg(int index = 0)
public bool AddParamsArg(int index)
{
if (ParamsArgIndex >= 0 // 方法是否包含可变参数
&& index >= 0 // 如果包含,则判断从哪个参数赋值
&& index >= ParamsArgIndex // 需要判断是否为可选参数的部分
&& index < ParameterDetailss.Length) // 防止下标越界
{
var newPd = ParameterDetailss[index].CloneOfModel(this.NodeModel); // 复制出属于本身节点的参数描述
newPd.Index = ParameterDetailss.Length; // 更新索引
newPd.IsParams = true;
ParameterDetailss = ArrayHelper.AddToArray(ParameterDetailss, newPd); // 新增
return true;
}
else
if (ParamsArgIndex < 0 // 方法是否包含可变参数
|| index < 0 // 如果包含,则判断从哪个参数赋值
|| index < ParamsArgIndex // 需要判断是否为可选参数的部分
|| index >= ParameterDetailss.Length) // 防止下标越界
{
return false;
}
var newPd = ParameterDetailss[index].CloneOfModel(this.NodeModel); // 复制出属于本身节点的参数描述
newPd.Index = ParameterDetailss.Length; // 更新索引
newPd.IsParams = true;
ParameterDetailss = ArrayHelper.AddToArray(ParameterDetailss, newPd); // 新增
return true;
}
public bool AddParamsArg(ParameterDetails parameterDetails)
{
if (ParamsArgIndex < 0) // 方法是否包含可变参数
{
return false;
}
if (parameterDetails is null)
{
return false;
}
parameterDetails.Index = ParameterDetailss.Length; // 更新索引
parameterDetails.IsParams = true;
ParameterDetailss = ArrayHelper.AddToArray(ParameterDetailss, parameterDetails); // 新增
return true;
}
/// <summary>
/// 移除可变参数
/// </summary>
/// <param name="index"></param>
public bool RemoveParamsArg(int index = 0)
public bool RemoveParamsArg(int index)
{
if (ParamsArgIndex >= 0 // 方法是否包含可变参数
&& index >= 0 // 如果包含,则判断从哪个参数赋值
&& index > ParamsArgIndex // 需要判断是否为可选参数的部分,并且不能删除原始的可变参数描述
&& index < ParameterDetailss.Length) // 防止下标越界
{
ParameterDetailss[index] = null; // 释放对象引用
var tmp = ArrayHelper.RemoteToArray<ParameterDetails>(ParameterDetailss, index); // 新增;
UpdateParamIndex(ref tmp);
ParameterDetailss = tmp; // 新增
return true;
}
else
if (ParamsArgIndex < 0 // 方法是否包含可变参数
|| index < 0 // 如果包含,则判断从哪个参数赋值
|| index <= ParamsArgIndex // 需要判断是否为可选参数的部分,并且不能删除原始的可变参数描述
|| index >= ParameterDetailss.Length) // 防止下标越界
{
return false;
}
ParameterDetailss[index] = null; // 释放对象引用
var tmp = ArrayHelper.RemoteToArray<ParameterDetails>(ParameterDetailss, index); // 新增;
UpdateParamIndex(ref tmp);
ParameterDetailss = tmp; // 新增
return true;
}
/// <summary>
/// 移除可变参数
/// </summary>
/// <param name="parameterDetails"></param>
public bool RemoveParamsArg(ParameterDetails parameterDetails)
{
if (ParamsArgIndex < 0) // 方法是否包含可变参数
{
return false;
}
if (parameterDetails is null)
{
return false;
}
int index = -1;
for (int i = 0; i < ParameterDetailss.Length; i++)
{
var pd = ParameterDetailss[i];
if (pd.Equals(parameterDetails))
{
index = i;
break;
}
}
if (index == -1)
{
return false;
}
ParameterDetailss[index] = null; // 释放对象引用
var tmp = ArrayHelper.RemoteToArray<ParameterDetails>(ParameterDetailss, index); // 新增;
UpdateParamIndex(ref tmp);
ParameterDetailss = tmp; // 新增
return true;
}
/// <summary>
/// 更新参数的索引
/// </summary>

View File

@@ -45,7 +45,7 @@ namespace Serein.Library
/// <summary>
/// 节点 数据、视图、VM 管理
/// </summary>
public class NodeMVVMManagement
public class NodeMVVMService
{
/// <summary>
/// 节点对应的控件类型

View File

@@ -246,7 +246,7 @@ namespace Serein.Library
var type = EnumHelper.GetBoundValue(ExplicitType, resultEnum, attr => attr.Value);
if (type is Type enumBindType && !(enumBindType is null))
{
var value = nodeModel.Env.IOC.CreateTempObject(enumBindType);
var value = nodeModel.Env.IOC.CreateObject(enumBindType);
return value;
}
}

View File

@@ -145,7 +145,7 @@ namespace Serein.Library.Web
return false; // 没有对应的处理配置
}
ControllerBase controllerInstance = (ControllerBase)SereinIOC.CreateTempObject(controllerType);
ControllerBase controllerInstance = (ControllerBase)SereinIOC.CreateObject(controllerType);
if (controllerInstance is null)
{

View File

@@ -9,7 +9,7 @@ namespace Serein.Library
/// <para>这种情况会导致流程启动时IOC容器无法注入构造函数并创建类型导致启动失败。</para>
/// <para>解决方法从ServiceA类的构造函数中移除ServiceB类型的入参将该类型更改为公开可见的可写属性成员ServiceB serviceB{get;set;},并在该属性上标记[AutoInjection]特性</para>
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public sealed class AutoInjectionAttribute : Attribute
{
}

View File

@@ -21,10 +21,19 @@ namespace Serein.Library
/// </summary>
public static readonly ConnectionInvokeType[] ConnectionTypes = new ConnectionInvokeType[]
{
ConnectionInvokeType.Upstream,
ConnectionInvokeType.Upstream,
ConnectionInvokeType.IsSucceed,
ConnectionInvokeType.IsFail,
ConnectionInvokeType.IsError,
};
/// <summary>
/// 节点连接关系种类
/// </summary>
public static readonly ConnectionArgSourceType[] ConnectionArgSourceTypes = new ConnectionArgSourceType[]
{
ConnectionArgSourceType.GetPreviousNodeData,
ConnectionArgSourceType.GetOtherNodeData,
ConnectionArgSourceType.GetOtherNodeDataOfInvoke,
};
}
}

View File

@@ -3,6 +3,7 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
@@ -122,7 +123,8 @@ namespace Serein.Library
/// <param name="class">级别</param>
public static void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.General)
{
SereinEnv.environment.WriteLine(type,message,@class);
Debug.WriteLine($"{type} : {message}");
SereinEnv.environment?.WriteLine(type,message,@class);
}
/// <summary>

View File

@@ -137,13 +137,13 @@ namespace Serein.Library.Utils
#endregion
#region
#region
/// <summary>
/// 用于临时实例的创建不登记到IOC容器中依赖项注入失败时也不记录。
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public object CreateTempObject(Type type)
public object CreateObject(Type type)
{
var ctors = GetConstructor(type); // 获取构造函数
object instance = null;
@@ -180,10 +180,55 @@ namespace Serein.Library.Utils
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T CreateTempObject<T>()
public T CreateObject<T>()
{
return (T)CreateTempObject(typeof(T));
}
return (T)CreateObject(typeof(T));
}
/// <summary>
/// 给定一个实例,尽可能地在该实例中具有[AutoInjection]特性的属性/字段上设置为IOC容器中已有的对应类型的对象。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="instance"></param>
/// <returns></returns>
public T InjectDependenciesProperty<T>(T instance)
{
var type = instance.GetType();
var properties = type.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToArray()
.Where(p => p.CanWrite // 可写属性
&& p.GetCustomAttribute<AutoInjectionAttribute>() != null // 有特性标注需要注入
&& p.GetValue(instance) == null); // 属性为空
// 属性注入
foreach (var property in properties)
{
var propertyType = property.PropertyType;
if (_dependencies.TryGetValue(propertyType.FullName, out var dependencyInstance))
{
property.SetValue(instance, dependencyInstance); // 尝试写入到目标实例的属性中
}
}
// 字段注入
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic )
.Where(f => f.GetCustomAttribute<AutoInjectionAttribute>() != null
&& f.GetValue(instance) == null);
foreach (var field in fields)
{
var fieldType = field.FieldType;
if (_dependencies.TryGetValue(fieldType.FullName, out var dependencyInstance))
{
field.SetValue(instance, dependencyInstance);
}
}
return instance;
}
#endregion
#region
@@ -257,56 +302,62 @@ namespace Serein.Library.Utils
public string Name { get; set; }
public Type Type { get; set; }
}
private const string FlowBaseClassName = "@LibraryRootNode";
private const string IOC_MAIN = "*Priority Instantiation*";
/// <summary>
/// 构建依赖关系树
/// <para>遍历所有需要注册的类型,获取到它们所有构造函数,并统计每个构造函数的入参类型,构建依赖关系树</para>
/// </summary>
/// <returns></returns>
/// <returns>“ID-PID”关系的树形结构</returns>
private Dictionary<string, List<string>> BuildDependencyTree()
{
var dependencyMap = new Dictionary<string, HashSet<string>>();
dependencyMap[FlowBaseClassName] = new HashSet<string>();
dependencyMap[IOC_MAIN] = new HashSet<string>(); // 优先实例化
foreach (var typeMapping in _typeMappings)
{
var constructors = GetConstructor(typeMapping.Value); // 获取构造函数
var typeFullName = typeMapping.Key; // 注册的类型 FullName
var type = typeMapping.Value; // 对应的Type。如果是以接口形式注册typeFullName将是接口类的FullName而type将是接口实现类。
var constructors = GetConstructor(type); // 获取构造函数
foreach (var constructor in constructors)
{
if (constructor != null)
if (constructor is null)
{
var parameters = constructor.GetParameters()
.Select(p => p.ParameterType)
.ToList();
if (parameters.Count == 0) // 无参的构造函数
continue;
}
var parameters = constructor.GetParameters().Select(p => p.ParameterType);
var ctorCount = constructors.Length;
var ctorParamCount = parameters.Count();
// 类型仅有一个构造函数,并且无参,将优先实例化
if (ctorCount == 1 && ctorParamCount == 0)
{
if (!dependencyMap[IOC_MAIN].Contains(type.FullName))
{
var type = typeMapping.Value;
if (!dependencyMap[FlowBaseClassName].Contains(type.FullName))
{
dependencyMap[FlowBaseClassName].Add(type.FullName);
}
dependencyMap[IOC_MAIN].Add(type.FullName);
}
continue;
}
// 从类型的有参构造函数中提取类型
foreach (var param in parameters)
{
if (!dependencyMap.TryGetValue(param.FullName, out var hashSet))
{
hashSet = new HashSet<string>();
hashSet.Add(typeMapping.Key);
dependencyMap.Add(param.FullName, hashSet);
}
else
{
// 从类型的有参构造函数中提取类型
foreach (var param in parameters)
if (!hashSet.Contains(typeMapping.Key))
{
if (!dependencyMap.TryGetValue(param.FullName, out var hashSet))
{
hashSet = new HashSet<string>();
hashSet.Add(typeMapping.Key);
dependencyMap.Add(param.FullName, hashSet);
}
else
{
if (!hashSet.Contains(typeMapping.Key))
{
hashSet.Add(typeMapping.Key);
}
}
hashSet.Add(typeMapping.Key);
}
}
}
}
}
@@ -315,7 +366,7 @@ namespace Serein.Library.Utils
}
/// <summary>
/// 获取类型的获取所有构造函数
/// 获取类型的所有构造函数,根据入参数量,由多到少排列
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
@@ -325,42 +376,46 @@ namespace Serein.Library.Utils
}
/// <summary>
/// 创建例的生成顺序
/// 创建例的生成顺序
/// </summary>
/// <param name="dependencyMap"></param>
/// <param name="dependencyMap">依赖关系树</param>
/// <returns></returns>
public List<string> GetCreationOrder(Dictionary<string, List<string>> dependencyMap)
{
var graph = new Dictionary<string, List<string>>();
var indegree = new Dictionary<string, int>();
var graph = new Dictionary<string, List<string>>(); // 另一种依赖关系树
var indegree = new Dictionary<string, int>(); // 表示出现次数
foreach (var entry in dependencyMap)
{
var key = entry.Key;
if (!graph.ContainsKey(key))
// “rootNode”是注册类的类型FullName属性
var rootNode = entry.Key; // 根节点
if (!graph.ContainsKey(rootNode))
{
graph[key] = new List<string>();
graph[rootNode] = new List<string>();
}
foreach (var dependent in entry.Value)
// “childNode”是注册类构造函数中出现过的参数的类型FullName属性
foreach (var childNode in entry.Value)
{
if (!graph.ContainsKey(dependent))
if (!graph.ContainsKey(childNode))
{
graph[dependent] = new List<string>();
graph[childNode] = new List<string>();
}
graph[key].Add(dependent);
graph[rootNode].Add(childNode);
// 更新入度
if (!indegree.ContainsKey(dependent))
if (!indegree.ContainsKey(childNode))
{
indegree[dependent] = 0;
indegree[childNode] = 0;
}
indegree[dependent]++;
indegree[childNode]++;
}
if (!indegree.ContainsKey(key))
if (!indegree.ContainsKey(rootNode))
{
indegree[key] = 0;
indegree[rootNode] = 0;
}
}
@@ -386,10 +441,10 @@ namespace Serein.Library.Utils
if (tmpList.Count > 0)
{
StringBuilder sb = new StringBuilder();
sb.Append("以下类型可能产生循环依赖,请避免循环依赖,如果确实需要循环引用,请使用 [AutoInjection] 特性注入属性");
sb.Append("以下类型存在循环依赖,请避免循环依赖,如果确实需要循环引用,请使用 [AutoInjection] 特性注入属性");
foreach (var kv in tmpList)
{
sb.AppendLine($"Class Name : {kv}");
sb.AppendLine($"类名 : {kv}");
}
SereinEnv.WriteLine(InfoType.ERROR, sb.ToString());
}
@@ -412,9 +467,9 @@ namespace Serein.Library.Utils
{
return instance;
}
if (_registerCallback.TryGetValue(typeName,out var obj))
if (_registerCallback.TryGetValue(typeName,out var getInstance))
{
instance = obj;
return getInstance.Invoke();
}
// 字符串、值类型,抽象类型,暂时不支持自动创建
@@ -427,7 +482,7 @@ namespace Serein.Library.Utils
{
// 没有显示指定构造函数入参,选择参数最多的构造函数
//var constructor = GetConstructorWithMostParameters(type);
var constructors = GetConstructor(type); // 获取参数最多的构造函数
var constructors = GetConstructor(type); // 获取构造函数
foreach(var constructor in constructors)
{
@@ -480,15 +535,16 @@ namespace Serein.Library.Utils
/// <returns></returns>
public ISereinIOC Build()
{
var dependencyTree = BuildDependencyTree();
var creationOrder = GetCreationOrder(dependencyTree);
var dependencyTree = BuildDependencyTree(); // 生成类型依赖关系
var creationOrder = GetCreationOrder(dependencyTree); // 生成创建顺序
// 输出创建顺序
Debug.WriteLine("创建顺序: " + string.Join(" → ", creationOrder));
Debug.WriteLine("创建顺序: " + string.Join($"{Environment.NewLine}↓ {Environment.NewLine}", creationOrder));
// 创建对象
foreach (var typeName in creationOrder)
{
if (_dependencies.ContainsKey(typeName))
{
continue;
@@ -496,6 +552,7 @@ namespace Serein.Library.Utils
var value = CreateInstance(typeName);
if(value is null)
{
SereinEnv.WriteLine(InfoType.ERROR, $"IOC容器无法创建对象{typeName}");
continue;
}
_dependencies[typeName] = value;