mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-12 04:29:25 +08:00
LocalFlowEnvironment文件丢失,需要重写
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
/// 节点保存时如若需要保存自定义数据,可通过该方法进行控制保存逻辑
|
||||
|
||||
@@ -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()方法。
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Serein.Library
|
||||
/// <summary>
|
||||
/// 节点 数据、视图、VM 管理
|
||||
/// </summary>
|
||||
public class NodeMVVMManagement
|
||||
public class NodeMVVMService
|
||||
{
|
||||
/// <summary>
|
||||
/// 节点对应的控件类型
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user