mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-20 00:06:45 +08:00
尝试使用源生成器规范NodeModel代码逻辑
This commit is contained in:
@@ -97,7 +97,7 @@ namespace Serein.Library.Utils
|
||||
/// </summary>
|
||||
/// <param name="signal">信号标识符</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
public CancelType CreateChannelWithTimeoutSync(string signal, TimeSpan timeout)
|
||||
public async Task<CancelType> CreateChannelWithTimeoutSync(string signal, TimeSpan timeout)
|
||||
{
|
||||
var channel = GetOrCreateChannel(signal);
|
||||
var cts = new CancellationTokenSource();
|
||||
@@ -119,7 +119,7 @@ namespace Serein.Library.Utils
|
||||
});
|
||||
|
||||
// 同步阻塞直到信号触发或超时
|
||||
var result = channel.Reader.ReadAsync().AsTask().GetAwaiter().GetResult();
|
||||
var result = await channel.Reader.ReadAsync();
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
103
Library/Utils/ChannelFlowTrigger.cs
Normal file
103
Library/Utils/ChannelFlowTrigger.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
|
||||
|
||||
|
||||
public class ChannelFlowTrigger<TSignal>
|
||||
{
|
||||
// 使用并发字典管理每个枚举信号对应的 Channel
|
||||
private readonly ConcurrentDictionary<TSignal, Channel<(TriggerType,object)>> _channels = new ConcurrentDictionary<TSignal, Channel<(TriggerType, object)>>();
|
||||
|
||||
/// <summary>
|
||||
/// 创建信号并指定超时时间,到期后自动触发(异步方法)
|
||||
/// </summary>
|
||||
/// <param name="signal">枚举信号标识符</param>
|
||||
/// <param name="outTime">超时时间</param>
|
||||
/// <returns>等待任务</returns>
|
||||
public async Task<(TriggerType, TResult)> WaitDataWithTimeoutAsync<TResult>(TSignal signal, TimeSpan outTime)
|
||||
{
|
||||
var channel = GetOrCreateChannel(signal);
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
// 异步任务:超时后自动触发信号
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(outTime, cts.Token);
|
||||
await channel.Writer.WriteAsync((TriggerType.Overtime, null));
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// 超时任务被取消
|
||||
}
|
||||
}, cts.Token);
|
||||
|
||||
// 等待信号传入(超时或手动触发)
|
||||
(var type, var result) = await channel.Reader.ReadAsync();
|
||||
|
||||
return (type, result.ToConvert<TResult>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建信号,直到触发
|
||||
/// </summary>
|
||||
/// <param name="signal">枚举信号标识符</param>
|
||||
/// <returns>等待任务</returns>
|
||||
public async Task<TResult> WaitData<TResult>(TSignal signal)
|
||||
{
|
||||
var channel = GetOrCreateChannel(signal);
|
||||
// 等待信号传入(超时或手动触发)
|
||||
(var type, var result) = await channel.Reader.ReadAsync();
|
||||
return result.ToConvert<TResult>();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 触发信号
|
||||
/// </summary>
|
||||
/// <param name="signal">枚举信号标识符</param>
|
||||
/// <returns>是否成功触发</returns>
|
||||
public bool TriggerSignal(TSignal signal, object value)
|
||||
{
|
||||
if (_channels.TryGetValue(signal, out var channel))
|
||||
{
|
||||
// 手动触发信号
|
||||
channel.Writer.TryWrite((TriggerType.External,value));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消所有任务
|
||||
/// </summary>
|
||||
public void CancelAllTasks()
|
||||
{
|
||||
foreach (var channel in _channels.Values)
|
||||
{
|
||||
channel.Writer.Complete();
|
||||
}
|
||||
_channels.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或创建指定信号的 Channel
|
||||
/// </summary>
|
||||
/// <param name="signal">枚举信号标识符</param>
|
||||
/// <returns>对应的 Channel</returns>
|
||||
private Channel<(TriggerType, object)> GetOrCreateChannel(TSignal signal)
|
||||
{
|
||||
return _channels.GetOrAdd(signal, _ => Channel.CreateUnbounded<(TriggerType, object)>());
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Library/Utils/DebounceHelper.cs
Normal file
48
Library/Utils/DebounceHelper.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息防抖
|
||||
/// </summary>
|
||||
public static class DebounceHelper
|
||||
{
|
||||
private static readonly ConcurrentDictionary<string, DateTime> _lastExecutionTimes = new ConcurrentDictionary<string, DateTime>();
|
||||
private static readonly object _lockObject = new object();
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否可以执行操作,根据传入的 key 和 debounceTime 来决定是否允许执行
|
||||
/// </summary>
|
||||
/// <param name="key">操作的唯一标识</param>
|
||||
/// <param name="debounceTimeInMs">防抖时间,单位为毫秒</param>
|
||||
/// <returns>如果可以执行操作,返回 true;否则返回 false</returns>
|
||||
public static bool CanExecute(string key, int debounceTimeInMs)
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
var currentTime = DateTime.Now;
|
||||
|
||||
if (_lastExecutionTimes.TryGetValue(key, out DateTime lastExecutionTime))
|
||||
{
|
||||
var timeSinceLastExecution = (currentTime - lastExecutionTime).TotalMilliseconds;
|
||||
|
||||
if (timeSinceLastExecution < debounceTimeInMs)
|
||||
{
|
||||
// 如果距离上次执行时间小于防抖时间,不允许执行
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新上次执行时间
|
||||
_lastExecutionTimes[key] = currentTime;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
using Serein.Library.Attributes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
|
||||
@@ -312,9 +312,13 @@ namespace Serein.Library.Utils
|
||||
string cacheKey = $"{type.FullName}.{methodInfo.Name}.MethodCallerAsync";
|
||||
return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateAsync(type, methodInfo));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表达式树构建无参数,有返回值(Task<object>)的方法(触发器)
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="methodInfo"></param>
|
||||
/// <returns></returns>
|
||||
private static Delegate CreateMethodCallerDelegateAsync(Type type, MethodInfo methodInfo)
|
||||
{
|
||||
var parameter = Expression.Parameter(typeof(object), "instance");
|
||||
@@ -336,6 +340,7 @@ namespace Serein.Library.Utils
|
||||
string cacheKey = $"{type.FullName}.{method.Name}.MethodCallerAsync";
|
||||
return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateAsync(type, method, parameterTypes));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表达式树构建多个参数,有返回值(Task<object>)的方法(触发器)
|
||||
/// </summary>
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.NodeFlow.Tool
|
||||
namespace Serein.Library
|
||||
{
|
||||
/// <summary>
|
||||
/// 触发类型
|
||||
|
||||
61
Library/Utils/MessageIdGenerator.cs
Normal file
61
Library/Utils/MessageIdGenerator.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息ID生成工具
|
||||
/// </summary>
|
||||
public class MessageIdGenerator
|
||||
{
|
||||
private static readonly object _lock = new object();
|
||||
private static int _counter = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 生成一个不重复的标识
|
||||
/// </summary>
|
||||
/// <param name="theme"></param>
|
||||
/// <returns></returns>
|
||||
public static string GenerateMessageId(string theme)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
// 时间戳
|
||||
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
|
||||
// 机器标识(可以替换成更加独特的标识,如机器的MAC地址等)
|
||||
string machineId = GetMachineId();
|
||||
|
||||
// 进程ID
|
||||
int processId = Process.GetCurrentProcess().Id;
|
||||
|
||||
// 递增计数器,确保在同一毫秒内的多次生成也不重复
|
||||
int count = _counter++;
|
||||
|
||||
// 随机数
|
||||
byte[] randomBytes = new byte[8];
|
||||
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
|
||||
{
|
||||
rng.GetBytes(randomBytes);
|
||||
}
|
||||
string randomPart = BitConverter.ToString(randomBytes).Replace("-", "");
|
||||
|
||||
// 将所有部分组合起来
|
||||
return $"{timestamp}-{machineId}-{processId}-{count}-{randomPart}-{theme}";
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetMachineId()
|
||||
{
|
||||
// 这里使用 GUID 模拟机器标识
|
||||
// 可以替换为更具体的机器信息
|
||||
return Guid.NewGuid().ToString("N");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
121
Library/Utils/RemoteEnvControl.cs
Normal file
121
Library/Utils/RemoteEnvControl.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using Newtonsoft.Json;
|
||||
using Serein.Library.Network.WebSocketCommunication;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// 管理远程环境,具备连接、发送消息、停止的功能
|
||||
/// </summary>
|
||||
public class RemoteEnvControl
|
||||
{
|
||||
/// <summary>
|
||||
/// 配置远程连接IP端口
|
||||
/// </summary>
|
||||
public RemoteEnvControl(string addres, int port, object token)
|
||||
{
|
||||
this.Addres = addres;
|
||||
this.Port = port;
|
||||
this.Token = token;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 远程环境的网络地址
|
||||
/// </summary>
|
||||
public string Addres { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 远程环境的对外端口
|
||||
/// </summary>
|
||||
public int Port { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 登录远程环境必须携带的token(可以为可序列化的JSON对象)
|
||||
/// </summary>
|
||||
public object Token { get; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 连接到远程的客户端
|
||||
/// </summary>
|
||||
public WebSocketClient EnvClient { get; } = new WebSocketClient();
|
||||
|
||||
/// <summary>
|
||||
/// 是否连接到了远程环境
|
||||
/// </summary>
|
||||
public bool IsConnectdRemoteEnv { get => isConnectdRemoteEnv; }
|
||||
private bool isConnectdRemoteEnv = false;
|
||||
|
||||
/// <summary>
|
||||
/// 尝试连接到远程环境
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> ConnectAsync()
|
||||
{
|
||||
// 第2种,WebSocket连接到远程环境,实时接收远程环境的响应?
|
||||
Console.WriteLine($"准备连接:{Addres}:{Port},{Token}");
|
||||
bool success = false;
|
||||
try
|
||||
{
|
||||
var tcpClient = new TcpClient();
|
||||
var result = tcpClient.BeginConnect(Addres, Port, null, null);
|
||||
success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(3));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
Console.WriteLine($"无法连通远程端口 {Addres}:{Port}");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var url = $"ws://{Addres}:{Port}/";
|
||||
var result = await EnvClient.ConnectAsync(url); // 尝试连接远程环境
|
||||
this.isConnectdRemoteEnv = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 发送消息
|
||||
/// </summary>
|
||||
/// <param name="theme"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public async Task SendAsync(string theme, object data)
|
||||
{
|
||||
var sendMsg = new
|
||||
{
|
||||
theme = theme,
|
||||
token = this.Token,
|
||||
data = data,
|
||||
};
|
||||
var msg = JsonConvert.SerializeObject(sendMsg);
|
||||
await EnvClient.SendAsync(msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.NodeFlow.Tool.SereinExpression.Resolver
|
||||
namespace Serein.Library.Utils.SereinExpression.Resolver
|
||||
{
|
||||
public class BoolConditionResolver : SereinConditionResolver
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.NodeFlow.Tool.SereinExpression.Resolver
|
||||
namespace Serein.Library.Utils.SereinExpression.Resolver
|
||||
{
|
||||
public class MemberConditionResolver<T> : SereinConditionResolver where T : struct, IComparable<T>
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.NodeFlow.Tool.SereinExpression.Resolver
|
||||
namespace Serein.Library.Utils.SereinExpression.Resolver
|
||||
{
|
||||
public class MemberStringConditionResolver : SereinConditionResolver
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.NodeFlow.Tool.SereinExpression.Resolver
|
||||
namespace Serein.Library.Utils.SereinExpression.Resolver
|
||||
{
|
||||
public class PassConditionResolver : SereinConditionResolver
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.NodeFlow.Tool.SereinExpression.Resolver
|
||||
namespace Serein.Library.Utils.SereinExpression.Resolver
|
||||
{
|
||||
public class StringConditionResolver : SereinConditionResolver
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.NodeFlow.Tool.SereinExpression.Resolver
|
||||
namespace Serein.Library.Utils.SereinExpression.Resolver
|
||||
{
|
||||
public class ValueTypeConditionResolver<T> : SereinConditionResolver where T : struct, IComparable<T>
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serein.Library.Utils;
|
||||
using Serein.NodeFlow.Tool.SereinExpression.Resolver;
|
||||
using Serein.Library.Utils.SereinExpression.Resolver;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Design;
|
||||
@@ -8,7 +8,7 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Serein.NodeFlow.Tool.SereinExpression
|
||||
namespace Serein.Library.Utils.SereinExpression
|
||||
{
|
||||
/// <summary>
|
||||
/// 字符串工具类
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace Serein.NodeFlow.Tool.SereinExpression
|
||||
namespace Serein.Library.Utils.SereinExpression
|
||||
{
|
||||
/// <summary>
|
||||
/// 条件解析抽象类
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
|
||||
namespace Serein.NodeFlow.Tool.SereinExpression
|
||||
namespace Serein.Library.Utils.SereinExpression
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用表达式操作/获取 对象的值
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Attributes;
|
||||
using Serein.Library.Web;
|
||||
using Serein.Library.Api;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IOC管理容器
|
||||
/// </summary>
|
||||
@@ -195,56 +190,60 @@ namespace Serein.Library.Utils
|
||||
public Type Type { get; set; }
|
||||
}
|
||||
private const string FlowBaseClassName = "<>$FlowBaseClass!@#";
|
||||
|
||||
|
||||
public Dictionary<string, List<string>> BuildDependencyTree()
|
||||
{
|
||||
var dependencyMap = new Dictionary<string, List<string>>();
|
||||
//var tmpTypeFullName = new HashSet<string>();
|
||||
//var tmpTypeFullName2 = new HashSet<string>();
|
||||
dependencyMap[FlowBaseClassName] = new List<string>();
|
||||
var dependencyMap = new Dictionary<string, HashSet<string>>();
|
||||
dependencyMap[FlowBaseClassName] = new HashSet<string>();
|
||||
foreach (var typeMapping in _typeMappings)
|
||||
{
|
||||
var constructor = GetConstructorWithMostParameters(typeMapping.Value); // 获取参数最多的构造函数
|
||||
if (constructor != null)
|
||||
//var constructor = GetConstructorWithMostParameters(typeMapping.Value); // 获取参数最多的构造函数
|
||||
|
||||
var constructors = GetConstructor(typeMapping.Value); // 获取参数最多的构造函数
|
||||
|
||||
foreach (var constructor in constructors)
|
||||
{
|
||||
var parameters = constructor.GetParameters()
|
||||
.Select(p => p.ParameterType)
|
||||
.ToList();
|
||||
//if(parameters.Count == 0)
|
||||
//{
|
||||
// if (!dependencyMap.ContainsKey(typeMapping.Value.FullName))
|
||||
// {
|
||||
// dependencyMap[typeMapping.Value.FullName] = new List<string>();
|
||||
// }
|
||||
// dependencyMap[typeMapping.Value.FullName].Add(typeMapping.Key);
|
||||
//}
|
||||
|
||||
|
||||
if(parameters .Count > 0)
|
||||
if (constructor != null)
|
||||
{
|
||||
// 从类型的构造函数中提取类型
|
||||
foreach (var param in parameters)
|
||||
var parameters = constructor.GetParameters()
|
||||
.Select(p => p.ParameterType)
|
||||
.ToList();
|
||||
if (parameters.Count == 0) // 无参的构造函数
|
||||
{
|
||||
if (!dependencyMap.ContainsKey(param.FullName))
|
||||
var type = typeMapping.Value;
|
||||
if (!dependencyMap[FlowBaseClassName].Contains(type.FullName))
|
||||
{
|
||||
dependencyMap[param.FullName] = new List<string>();
|
||||
dependencyMap[FlowBaseClassName].Add(type.FullName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 从类型的有参构造函数中提取类型
|
||||
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
|
||||
{
|
||||
if (!hashSet.Contains(typeMapping.Key))
|
||||
{
|
||||
hashSet.Add(typeMapping.Key);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
dependencyMap[param.FullName].Add(typeMapping.Key);
|
||||
//tmpTypeFullName.Add(param.FullName);
|
||||
//if (tmpTypeFullName2.Contains(param.FullName))
|
||||
//{
|
||||
// tmpTypeFullName2.Remove(param.FullName);
|
||||
//}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var type = typeMapping.Value;
|
||||
dependencyMap[FlowBaseClassName].Add(type.FullName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return dependencyMap;
|
||||
var tmp = dependencyMap.ToDictionary(key => key.Key, value => value.Value.ToList());
|
||||
return tmp;
|
||||
}
|
||||
// 获取参数最多的构造函数
|
||||
private ConstructorInfo GetConstructorWithMostParameters(Type type)
|
||||
@@ -253,6 +252,14 @@ namespace Serein.Library.Utils
|
||||
.OrderByDescending(c => c.GetParameters().Length)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
// 获取所有构造函数
|
||||
private ConstructorInfo[] GetConstructor(Type type)
|
||||
{
|
||||
return type.GetConstructors()
|
||||
.OrderByDescending(c => c.GetParameters().Length)
|
||||
.OrderBy(ctor => ctor.GetParameters().Length).ToArray();
|
||||
}
|
||||
|
||||
// 生成顺序
|
||||
public List<string> GetCreationOrder(Dictionary<string, List<string>> dependencyMap)
|
||||
{
|
||||
@@ -334,27 +341,57 @@ namespace Serein.Library.Utils
|
||||
{
|
||||
instance = Activator.CreateInstance(type, @params);
|
||||
}
|
||||
|
||||
// 字符串、值类型,抽象类型,暂时不支持自动创建
|
||||
if (type == typeof(string) || type.IsValueType || type.IsAbstract)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// 没有显示指定构造函数入参,选择参数最多的构造函数
|
||||
var constructor = GetConstructorWithMostParameters(type);
|
||||
var parameters = constructor.GetParameters();
|
||||
var args = new object[parameters.Length];
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
//var constructor = GetConstructorWithMostParameters(type);
|
||||
var constructors = GetConstructor(type); // 获取参数最多的构造函数
|
||||
|
||||
foreach(var constructor in constructors)
|
||||
{
|
||||
var argType = parameters[i].ParameterType;
|
||||
var fullName = parameters[i].ParameterType.FullName;
|
||||
if (!_dependencies.TryGetValue(fullName, out var argObj))
|
||||
var parameters = constructor.GetParameters();
|
||||
var args = new object[parameters.Length];
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
if (!_typeMappings.ContainsKey(fullName))
|
||||
var argType = parameters[i].ParameterType;
|
||||
var fullName = parameters[i].ParameterType.FullName;
|
||||
if (!_dependencies.TryGetValue(fullName, out var argObj))
|
||||
{
|
||||
_typeMappings.TryAdd(fullName, argType);
|
||||
if (!_typeMappings.ContainsKey(fullName))
|
||||
{
|
||||
_typeMappings.TryAdd(fullName, argType);
|
||||
}
|
||||
argObj = CreateInstance(fullName);
|
||||
if (argObj is null)
|
||||
{
|
||||
Console.WriteLine("构造参数创建失败"); //
|
||||
continue;
|
||||
}
|
||||
}
|
||||
argObj = CreateInstance(fullName);
|
||||
args[i] = argObj;
|
||||
}
|
||||
try
|
||||
{
|
||||
instance = Activator.CreateInstance(type, args);
|
||||
if(instance != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
args[i] = argObj;
|
||||
}
|
||||
instance = Activator.CreateInstance(type, args);
|
||||
|
||||
|
||||
}
|
||||
|
||||
InjectDependencies(instance); // 完成创建后注入实例需要的特性依赖项
|
||||
|
||||
64
Library/Utils/UIContextOperation.cs
Normal file
64
Library/Utils/UIContextOperation.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// 为类库提供了在UI线程上下文操作的方法
|
||||
/// </summary>
|
||||
public class UIContextOperation
|
||||
{
|
||||
private readonly SynchronizationContext context;
|
||||
|
||||
/// <summary>
|
||||
/// 传入UI线程上下文
|
||||
/// </summary>
|
||||
/// <param name="synchronizationContext">线程上下文</param>
|
||||
public UIContextOperation(SynchronizationContext synchronizationContext)
|
||||
{
|
||||
this.context = synchronizationContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步方式进行调用方法
|
||||
/// </summary>
|
||||
/// <param name="uiAction">要执行的UI操作</param>
|
||||
public void Invoke(Action uiAction)
|
||||
{
|
||||
context?.Post(state =>
|
||||
{
|
||||
uiAction?.Invoke();
|
||||
}, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步方式进行调用
|
||||
/// </summary>
|
||||
/// <param name="uiAction">要执行的UI操作</param>
|
||||
/// <returns></returns>
|
||||
public Task InvokeAsync(Action uiAction)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<bool>();
|
||||
|
||||
context?.Post(state =>
|
||||
{
|
||||
try
|
||||
{
|
||||
uiAction?.Invoke();
|
||||
tcs.SetResult(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
tcs.SetException(ex);
|
||||
}
|
||||
}, null);
|
||||
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user