mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
修改了IOC容器的实现,使其更加轻量
This commit is contained in:
@@ -5,106 +5,85 @@ using System.Text;
|
||||
namespace Serein.Library.Api
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>单例模式IOC容器,内部维护了一个实例字典,默认使用类型的FullName作为Key,如果以“接口-实现类”的方式注册,那么将使用接口类型的FullName作为Key。</para>
|
||||
/// <para>单例模式IOC容器,内部维护了一个实例字典,默认使用类型的FullName作为Key,</para>
|
||||
/// <para>如果以“接口-实现类”的方式注册,那么将使用接口类型的FullName作为Key。</para>
|
||||
/// <para>当某个类型注册绑定成功后,将不会因为其它地方尝试注册相同类型的行为导致类型被重新创建。</para>
|
||||
/// </summary>
|
||||
public interface ISereinIOC
|
||||
public interface ISereinIOC
|
||||
{
|
||||
/// <summary>
|
||||
/// 慎用,重置IOC容器,除非再次注册绑定,否则将导致不能创建注入依赖类的临时对象。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ISereinIOC Reset();
|
||||
|
||||
/// <summary>
|
||||
/// 注册实例,如果确定了params,那么将使用params入参构建实例对象。
|
||||
/// 通过指定类型的方式注册实例
|
||||
/// </summary>
|
||||
ISereinIOC Register(Type type, params object[] parameters);
|
||||
/// <summary>
|
||||
/// 通过泛型的方式注册实例,如果确定了params,那么将使用params入参构建实例对象。
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="parameters"></param>
|
||||
/// <param name="type">实例类型</param>
|
||||
/// <returns></returns>
|
||||
ISereinIOC Register<T>(params object[] parameters);
|
||||
ISereinIOC Register(Type type);
|
||||
|
||||
/// <summary>
|
||||
/// 通过指定类型的方式注册实例
|
||||
/// </summary>
|
||||
/// <param name="type">实例类型</param>
|
||||
/// <param name="getInstance">获取实例的回调函数</param>
|
||||
/// <returns></returns>
|
||||
ISereinIOC Register(Type type, Func<object> getInstance);
|
||||
|
||||
/// <summary>
|
||||
/// 通过泛型的方式注册实例
|
||||
/// </summary>
|
||||
/// <typeparam name="T">实例类型</typeparam>
|
||||
/// <param name="getInstance">获取实例的回调函数</param>
|
||||
/// <returns></returns>
|
||||
ISereinIOC Register<T>(Func<T> getInstance);
|
||||
|
||||
/// <summary>
|
||||
/// 注册接口的实例
|
||||
/// </summary>
|
||||
/// <typeparam name="TService">接口类型</typeparam>
|
||||
/// <typeparam name="TImplementation">实例类型</typeparam>
|
||||
/// <param name="parameters"></param>
|
||||
/// <param name="getInstance">获取实例的回调函数</param>
|
||||
/// <returns></returns>
|
||||
ISereinIOC Register<TService, TImplementation>(params object[] parameters) where TImplementation : TService;
|
||||
ISereinIOC Register<TService, TImplementation>(Func<TService> getInstance) where TImplementation : TService;
|
||||
|
||||
/// <summary>
|
||||
/// 指定一个Key登记一个持久化的实例。
|
||||
/// 注册接口的实现类
|
||||
/// </summary>
|
||||
/// <param name="key">登记使用的名称</param>
|
||||
/// <param name="instance">实例对象</param>
|
||||
/// <returns>是否注册成功</returns>
|
||||
bool RegisterPersistennceInstance(string key, object instance);
|
||||
|
||||
/// <summary>
|
||||
/// 指定一个Key登记一个实例。
|
||||
/// </summary>
|
||||
/// <param name="key">登记使用的名称</param>
|
||||
/// <param name="instance">实例对象</param>
|
||||
/// <returns>是否注册成功</returns>
|
||||
/// bool RegisterInstance(string key, object instance);
|
||||
/// <typeparam name="TService">接口类型</typeparam>
|
||||
/// <typeparam name="TImplementation">实例类型</typeparam>
|
||||
/// <returns></returns>
|
||||
ISereinIOC Register<TService, TImplementation>() where TImplementation : TService;
|
||||
|
||||
/// <summary>
|
||||
/// 获取类型的实例。如果需要获取的类型以“接口-实现类”的方式注册,请使用接口的类型。
|
||||
/// </summary>
|
||||
object Get(Type type);
|
||||
|
||||
/// <summary>
|
||||
/// 获取类型的实例。如果需要获取的类型以“接口-实现类”的方式注册,请使用接口的类型。
|
||||
/// </summary>
|
||||
T Get<T>();
|
||||
|
||||
/// <summary>
|
||||
/// <para>获取指定名称的实例。</para>
|
||||
/// <para>正常情况下应该使用 Get(Type type) / T Get<T>() 进行获取,但如果需要的实例是以CustomRegisterInstance()进行的登记,则需要通过这种方法进行获取。</para>
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="key">登记实例时使用的Key</param>
|
||||
/// <returns></returns>
|
||||
/// T Get<T>(string key);
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>创建实例并注入依赖项,不会注册到IOC容器中。</para>
|
||||
/// <para>使用场景:例如 View 的构造函数中需要创建 ViewModel,而 ViewModel 存在注册过的依赖项,可以通过该接口进行创建</para>
|
||||
/// <para>给定一个类型,由IOC容器负责创建实例,如果存在多个构造函数,将由参数最多的构造函数开始尝试创建。</para>
|
||||
/// <para></para>
|
||||
/// </summary>
|
||||
object Instantiate(Type type);
|
||||
object CreateTempObject(Type type);
|
||||
|
||||
/// <summary>
|
||||
/// <para>创建实例并注入依赖项,不会注册到IOC容器中。</para>
|
||||
/// <para>使用场景:例如 View 的构造函数中需要创建 ViewModel,而 ViewModel 存在注册过的依赖项,可以通过该接口进行创建</para>
|
||||
/// <para>给定一个类型,由IOC容器负责创建实例,如果存在多个构造函数,将由参数最多的构造函数开始尝试创建。</para>
|
||||
/// <para></para>
|
||||
/// </summary>
|
||||
T Instantiate<T>();
|
||||
T CreateTempObject<T>();
|
||||
|
||||
/// <summary>
|
||||
/// 通过已注册的类型,生成依赖关系,然后依次实例化并注入依赖项,最后登记到容器中。
|
||||
/// 搜寻已注册的类型生成依赖关系,依次实例化并注入依赖项,缓存在由IOC容器维护的Map中,直到手动调用Reset()方法。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ISereinIOC Build();
|
||||
|
||||
/// <summary>
|
||||
/// 从容器中获取某个类型的实例进行运行
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
ISereinIOC Run<T>(Action<T> action);
|
||||
ISereinIOC Run<T1, T2>(Action<T1, T2> action);
|
||||
ISereinIOC Run<T1, T2, T3>(Action<T1, T2, T3> action);
|
||||
ISereinIOC Run<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action);
|
||||
ISereinIOC Run<T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> action);
|
||||
ISereinIOC Run<T1, T2, T3, T4, T5, T6>(Action<T1, T2, T3, T4, T5, T6> action);
|
||||
ISereinIOC Run<T1, T2, T3, T4, T5, T6, T7>(Action<T1, T2, T3, T4, T5, T6, T7> action);
|
||||
ISereinIOC Run<T1, T2, T3, T4, T5, T6, T7, T8>(Action<T1, T2, T3, T4, T5, T6, T7, T8> action);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.Instantiate(enumBindType);
|
||||
var value = nodeModel.Env.IOC.CreateTempObject(enumBindType);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ namespace Serein.Library.Web
|
||||
return false; // 没有对应的处理配置
|
||||
}
|
||||
|
||||
ControllerBase controllerInstance = (ControllerBase)SereinIOC.Instantiate(controllerType);
|
||||
ControllerBase controllerInstance = (ControllerBase)SereinIOC.CreateTempObject(controllerType);
|
||||
|
||||
if (controllerInstance is null)
|
||||
{
|
||||
|
||||
@@ -15,56 +15,6 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消息ID生成器
|
||||
/// </summary>
|
||||
public class MsgIdHelper
|
||||
{
|
||||
private static readonly long _epoch = new DateTime(2023, 1, 1).Ticks; // 自定义起始时间
|
||||
private static long _lastTimestamp = -1L; // 上一次生成 ID 的时间戳
|
||||
private static long _sequence = 0L; // 序列号
|
||||
|
||||
/// <summary>
|
||||
/// 获取新的ID
|
||||
/// </summary>
|
||||
public static long NewId => GenerateId();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 生成消息ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static long GenerateId()
|
||||
{
|
||||
long timestamp = DateTime.UtcNow.Ticks;
|
||||
|
||||
// 如果时间戳是一样的,递增序列号
|
||||
if (timestamp == _lastTimestamp)
|
||||
{
|
||||
// 使用原子操作增加序列号
|
||||
_sequence = Interlocked.Increment(ref _sequence);
|
||||
if (_sequence > 999999) // 序列号最大值,6位
|
||||
{
|
||||
// 等待下一毫秒
|
||||
while (timestamp <= _lastTimestamp)
|
||||
{
|
||||
timestamp = DateTime.UtcNow.Ticks;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_sequence = 0; // 重置序列号
|
||||
}
|
||||
|
||||
_lastTimestamp = timestamp;
|
||||
|
||||
// 生成 ID:时间戳和序列号拼接
|
||||
return (timestamp - _epoch) * 1000 + _sequence; // 返回 ID
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
58
Library/Utils/MsgIdHelper.cs
Normal file
58
Library/Utils/MsgIdHelper.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息ID生成器
|
||||
/// </summary>
|
||||
public class MsgIdHelper
|
||||
{
|
||||
private static readonly long _epoch = new DateTime(2023, 1, 1).Ticks; // 自定义起始时间
|
||||
private static long _lastTimestamp = -1L; // 上一次生成 ID 的时间戳
|
||||
private static long _sequence = 0L; // 序列号
|
||||
|
||||
/// <summary>
|
||||
/// 获取新的ID
|
||||
/// </summary>
|
||||
public static long NewId => GenerateId();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 生成消息ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static long GenerateId()
|
||||
{
|
||||
long timestamp = DateTime.UtcNow.Ticks;
|
||||
|
||||
// 如果时间戳是一样的,递增序列号
|
||||
if (timestamp == _lastTimestamp)
|
||||
{
|
||||
// 使用原子操作增加序列号
|
||||
_sequence = Interlocked.Increment(ref _sequence);
|
||||
if (_sequence > 999999) // 序列号最大值,6位
|
||||
{
|
||||
// 等待下一毫秒
|
||||
while (timestamp <= _lastTimestamp)
|
||||
{
|
||||
timestamp = DateTime.UtcNow.Ticks;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_sequence = 0; // 重置序列号
|
||||
}
|
||||
|
||||
_lastTimestamp = timestamp;
|
||||
|
||||
// 生成 ID:时间戳和序列号拼接
|
||||
return (timestamp - _epoch) * 1000 + _sequence; // 返回 ID
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Serein.Library.Api;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Serein.Library.Api;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@@ -13,10 +14,8 @@ namespace Serein.Library.Utils
|
||||
/// <summary>
|
||||
/// IOC管理容器
|
||||
/// </summary>
|
||||
public class SereinIOC/* : ISereinIOC*/
|
||||
public class SereinIOC : ISereinIOC
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 类型集合,暂放待实例化的类型,完成实例化之后移除
|
||||
/// </summary>
|
||||
@@ -26,7 +25,11 @@ namespace Serein.Library.Utils
|
||||
/// 已完成注入的实例集合
|
||||
/// </summary>
|
||||
private readonly ConcurrentDictionary<string, object> _dependencies;
|
||||
private readonly ConcurrentDictionary<string, object[]> _registerParameterss;
|
||||
|
||||
/// <summary>
|
||||
/// 能够获取类型实例的闭包
|
||||
/// </summary>
|
||||
private readonly ConcurrentDictionary<string, Func<object>> _registerCallback;
|
||||
|
||||
/// <summary>
|
||||
/// 未完成注入的实例集合。
|
||||
@@ -35,107 +38,147 @@ namespace Serein.Library.Utils
|
||||
/// </summary>
|
||||
private readonly ConcurrentDictionary<string, List<(object,PropertyInfo)>> _unfinishedDependencies;
|
||||
|
||||
/// <summary>
|
||||
/// IOC容器成功创建了类型
|
||||
/// </summary>
|
||||
public event IOCMembersChangedHandler OnIOCMembersChanged;
|
||||
|
||||
/// <summary>
|
||||
/// 一个轻量级的IOC容器
|
||||
/// </summary>
|
||||
public SereinIOC()
|
||||
{
|
||||
_dependencies = new ConcurrentDictionary<string, object>();
|
||||
_registerParameterss = new ConcurrentDictionary<string, object[]>();
|
||||
_registerCallback = new ConcurrentDictionary<string, Func<object>>();
|
||||
_typeMappings = new ConcurrentDictionary<string, Type>();
|
||||
|
||||
_unfinishedDependencies = new ConcurrentDictionary<string, List<(object, PropertyInfo)>>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region 类型的注册
|
||||
/// <summary>
|
||||
/// 向容器注册类型
|
||||
/// </summary>
|
||||
/// <param name="type">需要注册的类型</param>
|
||||
/// <returns></returns>
|
||||
public ISereinIOC Register(Type type)
|
||||
{
|
||||
RegisterType(type.FullName, type);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册类型
|
||||
/// 向容器注册类型,并指定其实例成员
|
||||
/// </summary>
|
||||
/// <param name="type">目标类型</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
public bool Register(Type type, params object[] parameters)
|
||||
/// <param name="type">需要注册的类型</param>
|
||||
/// <param name="getInstance">获取实例的回调函数</param>
|
||||
/// <returns></returns>
|
||||
public ISereinIOC Register(Type type, Func<object> getInstance)
|
||||
{
|
||||
return RegisterType(type?.FullName, type, parameters);
|
||||
RegisterType(type.FullName, type, getInstance);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 注册类型
|
||||
/// 向容器注册类型,并指定其实例成员
|
||||
/// </summary>
|
||||
/// <param name="type">目标类型</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
public bool Register<T>(params object[] parameters)
|
||||
/// <typeparam name="T">需要注册的类型</typeparam>
|
||||
/// <param name="getInstance">获取实例的回调函数</param>
|
||||
/// <returns></returns>
|
||||
public ISereinIOC Register<T>(Func<T> getInstance)
|
||||
{
|
||||
var type = typeof(T);
|
||||
return RegisterType(type.FullName, type, parameters);
|
||||
RegisterType(type.FullName, type, () => getInstance.Invoke());
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 向容器注册接口类型,并指定其实例成员
|
||||
/// </summary>
|
||||
/// <typeparam name="TService">接口类型</typeparam>
|
||||
/// <typeparam name="TImplementation">实现类类型</typeparam>
|
||||
/// <param name="getInstance">获取实例的方法</param>
|
||||
/// <returns></returns>
|
||||
public ISereinIOC Register<TService, TImplementation>(Func<TService> getInstance)
|
||||
where TImplementation : TService
|
||||
{
|
||||
RegisterType(typeof(TService).FullName, typeof(TImplementation), () => getInstance.Invoke());
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册接口类型
|
||||
/// 向容器注册接口类型,其实例成员由容器自动创建
|
||||
/// </summary>
|
||||
/// <param name="type">目标类型</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
public bool Register<TService, TImplementation>(params object[] parameters)
|
||||
/// <typeparam name="TService">接口类型</typeparam>
|
||||
/// <typeparam name="TImplementation">实现类类型</typeparam>
|
||||
/// <returns></returns>
|
||||
public ISereinIOC Register<TService, TImplementation>()
|
||||
where TImplementation : TService
|
||||
{
|
||||
return RegisterType(typeof(TService).FullName, typeof(TImplementation), parameters);
|
||||
RegisterType(typeof(TService).FullName, typeof(TImplementation));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 示例的获取
|
||||
/// <summary>
|
||||
/// 用于临时实例的创建,不登记到IOC容器中,依赖项注入失败时也不记录。
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public object Instantiate(Type type)
|
||||
public object CreateTempObject(Type type)
|
||||
{
|
||||
var constructor = type.GetConstructors().First(); // 获取第一个构造函数
|
||||
var parameters = constructor.GetParameters(); // 获取参数列表
|
||||
var parameterValues = parameters.Select(param => ResolveDependency(param.ParameterType)).ToArray(); // 生成创建类型的入参参数
|
||||
var instance = Activator.CreateInstance(type, parameterValues); // 创建实例
|
||||
if (instance != null)
|
||||
var ctors = GetConstructor(type); // 获取构造函数
|
||||
object instance = null;
|
||||
// 从入参最多的构造函数开始构建对象
|
||||
foreach (var ctor in ctors)
|
||||
{
|
||||
|
||||
var parameters = ctor.GetParameters(); // 获取构造函数参数列表
|
||||
var parametersNames = parameters.Select(p => $"{p.ParameterType} {p.Name}");
|
||||
var parametersName = string.Join(", ", parametersNames);
|
||||
try
|
||||
{
|
||||
var parameterValues = parameters.Select(param => Get(param.ParameterType)).ToArray(); // 生成创建类型的入参参数
|
||||
instance = Activator.CreateInstance(type, parameterValues); // 创建实例
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex);
|
||||
SereinEnv.WriteLine(InfoType.INFO, $"在【{type}】类型上使用ctor({parametersName})构造函数时创建对象失败。错误信息:{ex.Message}");
|
||||
continue;
|
||||
}
|
||||
InjectDependencies(instance, false); // 完成创建后注入实例需要的特性依赖项
|
||||
break;
|
||||
}
|
||||
if (instance == null)
|
||||
{
|
||||
throw new Exception($"无法为【{type}】类型创建实例");
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public T Instantiate<T>()
|
||||
/// <summary>
|
||||
/// 用于临时实例的创建,不登记到IOC容器中,依赖项注入失败时也不记录。
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public T CreateTempObject<T>()
|
||||
{
|
||||
return (T)Instantiate(typeof(T));
|
||||
}
|
||||
return (T)CreateTempObject(typeof(T));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 通过名称记录或获取一个实例
|
||||
|
||||
/// <summary>
|
||||
/// 指定key值注册一个已经实例化的实例对象,并持久化储存
|
||||
/// 尝试获取指定类型的示例
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="instance"></param>
|
||||
public bool RegisterInstance(string key, object instance)
|
||||
{
|
||||
return RegisterPersistennceInstance(key, instance);
|
||||
}
|
||||
/// <summary>
|
||||
/// 指定key值注册一个已经实例化的实例对象,并持久化储存
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="instance"></param>
|
||||
public bool RegisterPersistennceInstance(string key, object instance)
|
||||
{
|
||||
// 不存在时才允许创建
|
||||
if (_dependencies.ContainsKey(key))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_dependencies.TryAdd(key, instance);
|
||||
//if (needInjectProperty)
|
||||
//{
|
||||
// InjectDependencies(instance); // 注入实例需要的依赖项
|
||||
//}
|
||||
//InjectUnfinishedDependencies(key, instance); // 检查是否存在其它实例需要该类型
|
||||
OnIOCMembersChanged?.Invoke(new IOCMembersChangedEventArgs(key, instance));
|
||||
return true;
|
||||
}
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public object Get(Type type)
|
||||
{
|
||||
var instance = Get(type.FullName);
|
||||
@@ -147,14 +190,15 @@ namespace Serein.Library.Utils
|
||||
return Get(type.FullName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试获取指定类型的示例
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public T Get<T>()
|
||||
{
|
||||
return (T)Get(typeof(T).FullName);
|
||||
}
|
||||
public T Get<T>(string name)
|
||||
{
|
||||
return (T)Get(name);
|
||||
}
|
||||
private object Get(string name)
|
||||
{
|
||||
if (!_dependencies.TryGetValue(name, out object value))
|
||||
@@ -172,7 +216,7 @@ namespace Serein.Library.Utils
|
||||
/// 清空容器对象
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool Reset()
|
||||
public ISereinIOC Reset()
|
||||
{
|
||||
// 检查是否存在非托管资源
|
||||
foreach (var instancei in _dependencies.Values)
|
||||
@@ -182,13 +226,14 @@ namespace Serein.Library.Utils
|
||||
disposable?.Dispose();
|
||||
}
|
||||
}
|
||||
_registerParameterss?.Clear();
|
||||
_registerCallback?.Clear();
|
||||
_unfinishedDependencies?.Clear();
|
||||
_typeMappings?.Clear();
|
||||
_dependencies?.Clear();
|
||||
return true;
|
||||
return this;
|
||||
}
|
||||
public class TypeKeyValue
|
||||
|
||||
class TypeKeyValue
|
||||
{
|
||||
public TypeKeyValue(string name, Type type)
|
||||
{
|
||||
@@ -198,19 +243,19 @@ namespace Serein.Library.Utils
|
||||
public string Name { get; set; }
|
||||
public Type Type { get; set; }
|
||||
}
|
||||
private const string FlowBaseClassName = "@FlowBaseClass";
|
||||
private const string FlowBaseClassName = "@LibraryRootNode";
|
||||
|
||||
|
||||
public Dictionary<string, List<string>> BuildDependencyTree()
|
||||
/// <summary>
|
||||
/// 构建依赖关系树
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private Dictionary<string, List<string>> BuildDependencyTree()
|
||||
{
|
||||
var dependencyMap = new Dictionary<string, HashSet<string>>();
|
||||
dependencyMap[FlowBaseClassName] = new HashSet<string>();
|
||||
foreach (var typeMapping in _typeMappings)
|
||||
{
|
||||
//var constructor = GetConstructorWithMostParameters(typeMapping.Value); // 获取参数最多的构造函数
|
||||
|
||||
var constructors = GetConstructor(typeMapping.Value); // 获取参数最多的构造函数
|
||||
|
||||
var constructors = GetConstructor(typeMapping.Value); // 获取构造函数
|
||||
foreach (var constructor in constructors)
|
||||
{
|
||||
if (constructor != null)
|
||||
@@ -254,22 +299,22 @@ namespace Serein.Library.Utils
|
||||
var tmp = dependencyMap.ToDictionary(key => key.Key, value => value.Value.ToList());
|
||||
return tmp;
|
||||
}
|
||||
// 获取参数最多的构造函数
|
||||
private ConstructorInfo GetConstructorWithMostParameters(Type type)
|
||||
{
|
||||
return type.GetConstructors()
|
||||
.OrderByDescending(c => c.GetParameters().Length)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
// 获取所有构造函数
|
||||
|
||||
/// <summary>
|
||||
/// 获取类型的获取所有构造函数
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
private ConstructorInfo[] GetConstructor(Type type)
|
||||
{
|
||||
return type.GetConstructors()
|
||||
//.OrderByDescending(c => c.GetParameters().Length)
|
||||
.OrderByDescending(ctor => ctor.GetParameters().Length).ToArray();
|
||||
return type.GetConstructors().OrderByDescending(ctor => ctor.GetParameters().Length).ToArray();
|
||||
}
|
||||
|
||||
// 生成顺序
|
||||
/// <summary>
|
||||
/// 创建示例的生成顺序
|
||||
/// </summary>
|
||||
/// <param name="dependencyMap"></param>
|
||||
/// <returns></returns>
|
||||
public List<string> GetCreationOrder(Dictionary<string, List<string>> dependencyMap)
|
||||
{
|
||||
var graph = new Dictionary<string, List<string>>();
|
||||
@@ -338,19 +383,24 @@ namespace Serein.Library.Utils
|
||||
return creationOrder;
|
||||
}
|
||||
|
||||
public object CreateInstance(string typeName)
|
||||
/// <summary>
|
||||
/// 创建实例对象
|
||||
/// </summary>
|
||||
/// <param name="typeName"></param>
|
||||
/// <returns></returns>
|
||||
private object CreateInstance(string typeName)
|
||||
{
|
||||
if (!_typeMappings.TryGetValue(typeName, out var type))
|
||||
if (!_typeMappings.TryGetValue(typeName, out var type)) // 获取类型
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (_dependencies.TryGetValue(typeName, out var instance))
|
||||
if (_dependencies.TryGetValue(typeName, out var instance)) // 获取实例
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
if (_registerParameterss.TryGetValue(typeName,out var @params))
|
||||
if (_registerCallback.TryGetValue(typeName,out var obj))
|
||||
{
|
||||
instance = Activator.CreateInstance(type, @params);
|
||||
instance = obj;
|
||||
}
|
||||
|
||||
// 字符串、值类型,抽象类型,暂时不支持自动创建
|
||||
@@ -410,8 +460,11 @@ namespace Serein.Library.Utils
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
public bool Build()
|
||||
/// <summary>
|
||||
/// 绑定所有类型,生成示例
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ISereinIOC Build()
|
||||
{
|
||||
var dependencyTree = BuildDependencyTree();
|
||||
var creationOrder = GetCreationOrder(dependencyTree);
|
||||
@@ -435,29 +488,29 @@ namespace Serein.Library.Utils
|
||||
OnIOCMembersChanged.Invoke(new IOCMembersChangedEventArgs(typeName, value));
|
||||
}
|
||||
_typeMappings.Clear();
|
||||
return true;
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 私有方法
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 注册类型
|
||||
/// </summary>
|
||||
/// <param name="typeFull"></param>
|
||||
/// <param name="type"></param>
|
||||
private bool RegisterType(string typeFull, Type type, params object[] parameters)
|
||||
/// <param name="typeFull">类型名称</param>
|
||||
/// <param name="type">要注册的类型</param>
|
||||
/// <param name="getInstance">获取实例的闭包</param>
|
||||
private bool RegisterType(string typeFull, Type type, Func<object> getInstance = null)
|
||||
{
|
||||
if (!_typeMappings.ContainsKey(typeFull))
|
||||
{
|
||||
_typeMappings[typeFull] = type;
|
||||
if(parameters.Length > 0)
|
||||
if(getInstance != null)
|
||||
{
|
||||
_registerParameterss[typeFull] = parameters;
|
||||
_registerCallback[typeFull] = getInstance;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -467,20 +520,11 @@ namespace Serein.Library.Utils
|
||||
}
|
||||
}
|
||||
|
||||
private object ResolveDependency(Type parameterType)
|
||||
{
|
||||
var obj = Get(parameterType);
|
||||
if (obj is null)
|
||||
{
|
||||
throw new InvalidOperationException($"构造函数注入时类型[{parameterType}]不存在实例");
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 如果其它实例想要该对象时,注入过去
|
||||
/// </summary>
|
||||
private void InjectUnfinishedDependencies(string key,object instance)
|
||||
private void InjectUnfinishedDependencies(string key, object instance)
|
||||
{
|
||||
if (_unfinishedDependencies.TryGetValue(key, out var unfinishedPropertyList))
|
||||
{
|
||||
@@ -534,14 +578,13 @@ namespace Serein.Library.Utils
|
||||
}
|
||||
|
||||
|
||||
public void Run<T>(Action<T> action)
|
||||
private void Run<T>(Action<T> action)
|
||||
{
|
||||
var service = Get<T>();
|
||||
action(service);
|
||||
|
||||
}
|
||||
|
||||
public void Run<T1, T2>(Action<T1, T2> action)
|
||||
private void Run<T1, T2>(Action<T1, T2> action)
|
||||
{
|
||||
var service1 = Get<T1>();
|
||||
var service2 = Get<T2>();
|
||||
@@ -549,7 +592,7 @@ namespace Serein.Library.Utils
|
||||
action(service1, service2);
|
||||
}
|
||||
|
||||
public void Run<T1, T2, T3>(Action<T1, T2, T3> action)
|
||||
private void Run<T1, T2, T3>(Action<T1, T2, T3> action)
|
||||
{
|
||||
var service1 = Get<T1>();
|
||||
var service2 = Get<T2>();
|
||||
@@ -557,7 +600,7 @@ namespace Serein.Library.Utils
|
||||
action(service1, service2, service3);
|
||||
}
|
||||
|
||||
public void Run<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action)
|
||||
private void Run<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action)
|
||||
{
|
||||
var service1 = Get<T1>();
|
||||
var service2 = Get<T2>();
|
||||
@@ -566,7 +609,7 @@ namespace Serein.Library.Utils
|
||||
action(service1, service2, service3, service4);
|
||||
}
|
||||
|
||||
public void Run<T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> action)
|
||||
private void Run<T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> action)
|
||||
{
|
||||
var service1 = Get<T1>();
|
||||
var service2 = Get<T2>();
|
||||
@@ -576,7 +619,7 @@ namespace Serein.Library.Utils
|
||||
action(service1, service2, service3, service4, service5);
|
||||
}
|
||||
|
||||
public void Run<T1, T2, T3, T4, T5, T6>(Action<T1, T2, T3, T4, T5, T6> action)
|
||||
private void Run<T1, T2, T3, T4, T5, T6>(Action<T1, T2, T3, T4, T5, T6> action)
|
||||
{
|
||||
var service1 = Get<T1>();
|
||||
var service2 = Get<T2>();
|
||||
@@ -587,7 +630,7 @@ namespace Serein.Library.Utils
|
||||
action(service1, service2, service3, service4, service5, service6);
|
||||
}
|
||||
|
||||
public void Run<T1, T2, T3, T4, T5, T6, T7>(Action<T1, T2, T3, T4, T5, T6, T7> action)
|
||||
private void Run<T1, T2, T3, T4, T5, T6, T7>(Action<T1, T2, T3, T4, T5, T6, T7> action)
|
||||
{
|
||||
var service1 = Get<T1>();
|
||||
var service2 = Get<T2>();
|
||||
@@ -599,7 +642,7 @@ namespace Serein.Library.Utils
|
||||
action(service1, service2, service3, service4, service5, service6, service7);
|
||||
}
|
||||
|
||||
public void Run<T1, T2, T3, T4, T5, T6, T7, T8>(Action<T1, T2, T3, T4, T5, T6, T7, T8> action)
|
||||
private void Run<T1, T2, T3, T4, T5, T6, T7, T8>(Action<T1, T2, T3, T4, T5, T6, T7, T8> action)
|
||||
{
|
||||
var service1 = Get<T1>();
|
||||
var service2 = Get<T2>();
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Net462DllTest
|
||||
if (ViewModel is null)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.INFO, "创建对象并注入依赖项");
|
||||
ViewModel = env.IOC.Instantiate<FromWorkBenchViewModel>();
|
||||
ViewModel = env.IOC.CreateTempObject<FromWorkBenchViewModel>();
|
||||
}
|
||||
BindData();
|
||||
}
|
||||
|
||||
@@ -64,9 +64,9 @@ namespace Serein.NodeFlow.Env
|
||||
#endregion
|
||||
|
||||
#region 注册基本服务类
|
||||
PersistennceInstance.Add(typeof(FlowInterruptTool).FullName, new FlowInterruptTool()); // 缓存流程实例
|
||||
PersistennceInstance.Add(typeof(IFlowEnvironment).FullName, (FlowEnvironment)this); // 缓存流程实例
|
||||
PersistennceInstance.Add(typeof(ISereinIOC).FullName, this); // 缓存容器服务
|
||||
PersistennceInstance.Add(typeof(FlowInterruptTool), new FlowInterruptTool()); // 缓存流程实例
|
||||
PersistennceInstance.Add(typeof(IFlowEnvironment), (FlowEnvironment)this); // 缓存流程实例
|
||||
PersistennceInstance.Add(typeof(ISereinIOC), this); // 缓存容器服务
|
||||
|
||||
ReRegisterPersistennceInstance();
|
||||
|
||||
@@ -293,7 +293,7 @@ namespace Serein.NodeFlow.Env
|
||||
/// <summary>
|
||||
/// 本地运行环境缓存的持久化实例
|
||||
/// </summary>
|
||||
private Dictionary<string, object> PersistennceInstance { get; } = new Dictionary<string, object>();
|
||||
private Dictionary<Type, object> PersistennceInstance { get; } = new Dictionary<Type, object>();
|
||||
|
||||
/// <summary>
|
||||
/// 环境加载的节点集合
|
||||
@@ -1428,13 +1428,13 @@ namespace Serein.NodeFlow.Env
|
||||
/// <param name="uiContextOperation"></param>
|
||||
public void SetUIContextOperation(UIContextOperation uiContextOperation)
|
||||
{
|
||||
this.UIContextOperation = uiContextOperation;
|
||||
var fullName = typeof(UIContextOperation).FullName;
|
||||
if (!string.IsNullOrEmpty(fullName))
|
||||
if(uiContextOperation is not null)
|
||||
{
|
||||
PersistennceInstance[fullName] = uiContextOperation; // 缓存封装好的UI线程上下文
|
||||
|
||||
this.UIContextOperation = uiContextOperation;
|
||||
PersistennceInstance[typeof(UIContextOperation)] = uiContextOperation; // 缓存封装好的UI线程上下文
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -2150,7 +2150,7 @@ namespace Serein.NodeFlow.Env
|
||||
{
|
||||
foreach (var kvp in PersistennceInstance)
|
||||
{
|
||||
IOC.RegisterPersistennceInstance(kvp.Key, kvp.Value);
|
||||
IOC.Register(kvp.Key, () => kvp.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2182,21 +2182,32 @@ namespace Serein.NodeFlow.Env
|
||||
return this;
|
||||
}
|
||||
|
||||
ISereinIOC ISereinIOC.Register(Type type, params object[] parameters)
|
||||
ISereinIOC ISereinIOC.Register(Type type)
|
||||
{
|
||||
sereinIOC.Register(type, parameters);
|
||||
sereinIOC.Register(type);
|
||||
return this;
|
||||
}
|
||||
ISereinIOC ISereinIOC.Register(Type type, Func<object> getInstance)
|
||||
{
|
||||
sereinIOC.Register(type, getInstance);
|
||||
return this;
|
||||
}
|
||||
|
||||
ISereinIOC ISereinIOC.Register<T>(params object[] parameters)
|
||||
ISereinIOC ISereinIOC.Register<T>(Func<T> getInstance)
|
||||
{
|
||||
sereinIOC.Register<T>(parameters);
|
||||
sereinIOC.Register<T>(getInstance);
|
||||
return this;
|
||||
}
|
||||
|
||||
ISereinIOC ISereinIOC.Register<TService, TImplementation>(params object[] parameters)
|
||||
ISereinIOC ISereinIOC.Register<TService, TImplementation>()
|
||||
{
|
||||
sereinIOC.Register<TService, TImplementation>(parameters);
|
||||
sereinIOC.Register<TService, TImplementation>();
|
||||
return this;
|
||||
}
|
||||
|
||||
ISereinIOC ISereinIOC.Register<TService, TImplementation>(Func<TService> getInstance)
|
||||
{
|
||||
sereinIOC.Register<TService, TImplementation>(getInstance);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -2226,11 +2237,6 @@ namespace Serein.NodeFlow.Env
|
||||
//}
|
||||
|
||||
|
||||
bool ISereinIOC.RegisterPersistennceInstance(string key, object instance)
|
||||
{
|
||||
PersistennceInstance.TryAdd(key, instance); // 记录需要持久化的实例
|
||||
return sereinIOC.RegisterPersistennceInstance(key, instance);
|
||||
}
|
||||
|
||||
//bool ISereinIOC.RegisterInstance(string key, object instance)
|
||||
//{
|
||||
@@ -2238,13 +2244,13 @@ namespace Serein.NodeFlow.Env
|
||||
//}
|
||||
|
||||
|
||||
object ISereinIOC.Instantiate(Type type)
|
||||
object ISereinIOC.CreateTempObject(Type type)
|
||||
{
|
||||
return sereinIOC.Instantiate(type);
|
||||
return sereinIOC.CreateTempObject(type);
|
||||
}
|
||||
T ISereinIOC.Instantiate<T>()
|
||||
T ISereinIOC.CreateTempObject<T>()
|
||||
{
|
||||
return sereinIOC.Instantiate<T>();
|
||||
return sereinIOC.CreateTempObject<T>();
|
||||
}
|
||||
ISereinIOC ISereinIOC.Build()
|
||||
{
|
||||
@@ -2252,53 +2258,7 @@ namespace Serein.NodeFlow.Env
|
||||
return this;
|
||||
}
|
||||
|
||||
ISereinIOC ISereinIOC.Run<T>(Action<T> action)
|
||||
{
|
||||
sereinIOC.Run(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
ISereinIOC ISereinIOC.Run<T1, T2>(Action<T1, T2> action)
|
||||
{
|
||||
sereinIOC.Run(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
ISereinIOC ISereinIOC.Run<T1, T2, T3>(Action<T1, T2, T3> action)
|
||||
{
|
||||
sereinIOC.Run(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
ISereinIOC ISereinIOC.Run<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action)
|
||||
{
|
||||
sereinIOC.Run(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
ISereinIOC ISereinIOC.Run<T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> action)
|
||||
{
|
||||
sereinIOC.Run(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
ISereinIOC ISereinIOC.Run<T1, T2, T3, T4, T5, T6>(Action<T1, T2, T3, T4, T5, T6> action)
|
||||
{
|
||||
sereinIOC.Run(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
ISereinIOC ISereinIOC.Run<T1, T2, T3, T4, T5, T6, T7>(Action<T1, T2, T3, T4, T5, T6, T7> action)
|
||||
{
|
||||
sereinIOC.Run(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
ISereinIOC ISereinIOC.Run<T1, T2, T3, T4, T5, T6, T7, T8>(Action<T1, T2, T3, T4, T5, T6, T7, T8> action)
|
||||
{
|
||||
sereinIOC.Run(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
@@ -642,11 +642,6 @@ namespace Serein.NodeFlow.Env
|
||||
return IOC.Build();
|
||||
}
|
||||
|
||||
public bool RegisterPersistennceInstance(string key, object instance)
|
||||
{
|
||||
return IOC.RegisterPersistennceInstance(key, instance);
|
||||
}
|
||||
|
||||
//public bool RegisterInstance(string key, object instance)
|
||||
//{
|
||||
// return IOC.RegisterInstance(key, instance);
|
||||
@@ -667,29 +662,39 @@ namespace Serein.NodeFlow.Env
|
||||
// return IOC.Get<T>(key);
|
||||
//}
|
||||
|
||||
public object Instantiate(Type type)
|
||||
public object CreateTempObject(Type type)
|
||||
{
|
||||
return IOC.Instantiate(type);
|
||||
return IOC.CreateTempObject(type);
|
||||
}
|
||||
|
||||
public T Instantiate<T>()
|
||||
public T CreateTempObject<T>()
|
||||
{
|
||||
return IOC.Instantiate<T>();
|
||||
return IOC.CreateTempObject<T>();
|
||||
}
|
||||
|
||||
public ISereinIOC Register(Type type, params object[] parameters)
|
||||
public ISereinIOC Register(Type type)
|
||||
{
|
||||
return IOC.Register(type, parameters);
|
||||
return IOC.Register(type);
|
||||
}
|
||||
|
||||
public ISereinIOC Register<T>(params object[] parameters)
|
||||
public ISereinIOC Register(Type type, Func<object> getInstance)
|
||||
{
|
||||
return IOC.Register<T>(parameters);
|
||||
return IOC.Register(type, getInstance);
|
||||
}
|
||||
|
||||
public ISereinIOC Register<TService, TImplementation>(params object[] parameters) where TImplementation : TService
|
||||
public ISereinIOC Register<T>(Func<T> getInstance)
|
||||
{
|
||||
return IOC.Register<TService, TImplementation>(parameters);
|
||||
return IOC.Register<T>(getInstance);
|
||||
}
|
||||
|
||||
public ISereinIOC Register<TService, TImplementation>(Func<TService> getInstance) where TImplementation : TService
|
||||
{
|
||||
return IOC.Register<TService, TImplementation>(getInstance);
|
||||
}
|
||||
|
||||
public ISereinIOC Register<TService, TImplementation>() where TImplementation : TService
|
||||
{
|
||||
return IOC.Register<TService, TImplementation>();
|
||||
}
|
||||
|
||||
public ISereinIOC Reset()
|
||||
@@ -697,47 +702,6 @@ namespace Serein.NodeFlow.Env
|
||||
return IOC.Reset();
|
||||
}
|
||||
|
||||
public ISereinIOC Run<T>(Action<T> action)
|
||||
{
|
||||
return IOC.Run(action);
|
||||
}
|
||||
|
||||
public ISereinIOC Run<T1, T2>(Action<T1, T2> action)
|
||||
{
|
||||
return IOC.Run(action);
|
||||
}
|
||||
|
||||
public ISereinIOC Run<T1, T2, T3>(Action<T1, T2, T3> action)
|
||||
{
|
||||
return IOC.Run(action);
|
||||
}
|
||||
|
||||
public ISereinIOC Run<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action)
|
||||
{
|
||||
return IOC.Run(action);
|
||||
}
|
||||
|
||||
public ISereinIOC Run<T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> action)
|
||||
{
|
||||
return IOC.Run(action);
|
||||
}
|
||||
|
||||
public ISereinIOC Run<T1, T2, T3, T4, T5, T6>(Action<T1, T2, T3, T4, T5, T6> action)
|
||||
{
|
||||
return IOC.Run(action);
|
||||
}
|
||||
|
||||
public ISereinIOC Run<T1, T2, T3, T4, T5, T6, T7>(Action<T1, T2, T3, T4, T5, T6, T7> action)
|
||||
{
|
||||
return IOC.Run(action);
|
||||
}
|
||||
|
||||
public ISereinIOC Run<T1, T2, T3, T4, T5, T6, T7, T8>(Action<T1, T2, T3, T4, T5, T6, T7, T8> action)
|
||||
{
|
||||
return IOC.Run(action);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -201,7 +201,8 @@ namespace Serein.NodeFlow
|
||||
var pool = WorkOptions.FlowContextPool;
|
||||
var ioc = WorkOptions.Environment.IOC;
|
||||
|
||||
ioc.Run<FlowInterruptTool>(fit => fit.CancelAllTrigger());// 取消所有中断
|
||||
var fit = ioc.Get<FlowInterruptTool>();
|
||||
fit.CancelAllTrigger(); // 取消所有中断
|
||||
foreach (var md in mds) // 结束时
|
||||
{
|
||||
if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化
|
||||
|
||||
Reference in New Issue
Block a user