1. 重新设计了Generate项目及相关特性的命名,避免与其他类型混淆。

2. 补充了部分注释。
3. 修改了删除容器节点时,容器内子节点未正确删除的问题。
This commit is contained in:
fengjiayi
2025-07-30 21:15:07 +08:00
parent 93148b11a5
commit 152077e9b5
188 changed files with 2713 additions and 1406 deletions

View File

@@ -6,6 +6,9 @@ using System.Threading.Tasks;
namespace Serein.Library.Utils
{
/// <summary>
/// 数组操作的工具类
/// </summary>
public class ArrayHelper
{

View File

@@ -270,6 +270,14 @@ namespace Serein.Library.Utils
return (T)result;
}
/// <summary>
/// 将字符串转换为指定类型的值对象。
/// </summary>
/// <param name="valueStr"></param>
/// <param name="type"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public static object ToValueData(this string valueStr, Type type)
{
if (string.IsNullOrWhiteSpace(valueStr))

View File

@@ -41,21 +41,40 @@ namespace Serein.Library.Utils
return null;
}
/// <summary>
/// 解析字典属性并创建对象实例
/// </summary>
/// <param name="properties"></param>
/// <param name="typeName"></param>
/// <returns></returns>
public static object Resolve(IDictionary<string, object> properties, string typeName)
{
var obj = CreateObjectWithProperties(properties, typeName);
//SetPropertyValues(obj, properties);
return obj;
}
/// <summary>
/// 尝试解析字典属性并创建对象实例
/// </summary>
/// <param name="properties"></param>
/// <param name="typeName"></param>
/// <param name="result"></param>
/// <returns></returns>
public static bool TryResolve(IDictionary<string, object> properties, string typeName, out object result)
{
result = CreateObjectWithProperties(properties, typeName);
bool success = SetPropertyValuesWithValidation(result, properties);
return success;
// 打印赋值结果
}
// 递归方法:打印对象属性及类型
/// <summary>
/// 打印对象属性及类型
/// </summary>
/// <param name="obj"></param>
/// <param name="indent"></param>
public static void PrintObjectProperties(object obj, string indent = "")
{
var objType = obj.GetType();
@@ -327,7 +346,12 @@ namespace Serein.Library.Utils
}
#region
// 方法 1: 创建动态类型及其对象实例
/// <summary>
/// 创建动态类型及其对象实例
/// </summary>
/// <param name="properties"></param>
/// <param name="typeName"></param>
/// <returns></returns>
public static object CreateObjectWithProperties(IDictionary<string, object> properties, string typeName)
{
// 如果类型已经缓存,直接返回缓存的类型
@@ -410,8 +434,12 @@ namespace Serein.Library.Utils
return Activator.CreateInstance(dynamicType);
}
// 方法 2: 递归设置对象的属性值
public static void SetPropertyValues(object obj, Dictionary<string, object> properties)
/// <summary>
/// 递归设置对象的属性值
/// </summary>
/// <param name="obj"></param>
/// <param name="properties"></param>
private static void SetPropertyValues(object obj, Dictionary<string, object> properties)
{
var objType = obj.GetType();
@@ -439,8 +467,13 @@ namespace Serein.Library.Utils
}
}
}
// 方法 2: 递归设置对象的属性值(带验证)
/// <summary>
/// 递归设置对象的属性值(带验证)
/// </summary>
/// <param name="obj"></param>
/// <param name="properties"></param>
/// <returns></returns>
public static bool SetPropertyValuesWithValidation(object obj, IDictionary<string, object> properties)
{
var objType = obj.GetType();

View File

@@ -9,12 +9,15 @@ using System.Threading.Tasks;
namespace Serein.Library.Utils
{
/// <summary>
/// Emit创建委托工具类
/// </summary>
public class EmitHelper
{
/// <summary>
/// 动态方法信息
/// </summary>
public class EmitMethodInfo
{
/// <summary>
@@ -39,6 +42,9 @@ namespace Serein.Library.Utils
}
/// <summary>
/// 方法类型枚举
/// </summary>
public enum EmitMethodType
{
/// <summary>
@@ -55,12 +61,19 @@ namespace Serein.Library.Utils
TaskHasResult,
}
public static bool IsGenericTask(Type returnType, out Type taskResult)
/// <summary>
/// 判断一个类型是否为泛型 Task&lt;T&gt; 或 Task并返回泛型参数类型如果有的话
/// </summary>
/// <param name="returnType"></param>
/// <param name="taskResult"></param>
/// <returns></returns>
#nullable enable
public static bool IsGenericTask(Type returnType, out Type? taskResult)
{
// 判断是否为 Task 类型或泛型 Task<T>
if (returnType == typeof(Task))
{
taskResult = null;
taskResult = typeof(void);
return true;
}
else if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
@@ -78,7 +91,6 @@ namespace Serein.Library.Utils
}
}
/// <summary>
/// 根据方法信息创建动态调用的委托,返回方法类型,以及传出一个委托
/// </summary>
@@ -87,6 +99,10 @@ namespace Serein.Library.Utils
/// <returns></returns>
public static EmitMethodInfo CreateDynamicMethod(MethodInfo methodInfo,out Delegate @delegate)
{
if (methodInfo.DeclaringType == null)
{
throw new ArgumentNullException(nameof(methodInfo.DeclaringType));
}
EmitMethodInfo emitMethodInfo = new EmitMethodInfo();
bool IsTask = IsGenericTask(methodInfo.ReturnType, out var taskGenericsType);
bool IsTaskGenerics = taskGenericsType != null;
@@ -219,6 +235,10 @@ namespace Serein.Library.Utils
{
if (fieldInfo == null)
throw new ArgumentNullException(nameof(fieldInfo));
if (fieldInfo.DeclaringType == null)
throw new ArgumentNullException(nameof(fieldInfo.DeclaringType));
var method = new DynamicMethod(
fieldInfo.Name + "_Get",
@@ -257,6 +277,8 @@ namespace Serein.Library.Utils
{
if (fieldInfo == null)
throw new ArgumentNullException(nameof(fieldInfo));
if (fieldInfo.DeclaringType == null)
throw new ArgumentNullException(nameof(fieldInfo.DeclaringType));
if (fieldInfo.IsInitOnly)
throw new InvalidOperationException($"字段 {fieldInfo.Name} 是只读字段,无法设置值。");
@@ -299,6 +321,8 @@ namespace Serein.Library.Utils
{
if (propertyInfo == null)
throw new ArgumentNullException(nameof(propertyInfo));
if (propertyInfo.DeclaringType == null)
throw new ArgumentNullException(nameof(propertyInfo.DeclaringType));
var getMethod = propertyInfo.GetGetMethod(true);
if (getMethod == null)
throw new InvalidOperationException($"属性 {propertyInfo.Name} 没有可用的 Getter。");
@@ -339,6 +363,9 @@ namespace Serein.Library.Utils
{
if (propertyInfo == null)
throw new ArgumentNullException(nameof(propertyInfo));
if (propertyInfo.DeclaringType == null)
throw new ArgumentNullException(nameof(propertyInfo.DeclaringType));
var setMethod = propertyInfo.GetSetMethod(true);
if (setMethod == null)
throw new InvalidOperationException($"属性 {propertyInfo.Name} 没有可用的 Setter。");

View File

@@ -59,6 +59,13 @@ namespace Serein.Library.Utils
return attribute != null ? (TResult)valueSelector(attribute) : default;
}
/// <summary>
/// 从枚举值的 BindValueAttribute 特性中 获取绑定的参数(用于绑定了某些内容的枚举值)
/// </summary>
/// <param name="enumType"></param>
/// <param name="enumValue"></param>
/// <param name="valueSelector"></param>
/// <returns></returns>
public static object GetBoundValue(Type enumType,object enumValue, Func<BindValueAttribute, object> valueSelector)
{
var fieldInfo = enumType.GetField(enumValue.ToString());

View File

@@ -146,7 +146,7 @@ namespace Serein.Library.Utils
var parameter = Expression.Parameter(typeof(object), "instance");
var methodCall = Expression.Call(Expression.Convert(parameter, type), methodInfo);
if (IsGenericTask(methodInfo.ReturnType, out var taskResult))
if (EmitHelper.IsGenericTask(methodInfo.ReturnType, out var taskResult))
{
if (taskResult is null)
{
@@ -278,7 +278,7 @@ namespace Serein.Library.Utils
convertedArgs
);
if (IsGenericTask(methodInfo.ReturnType, out var taskResult))
if (EmitHelper.IsGenericTask(methodInfo.ReturnType, out var taskResult))
{
if (taskResult is null)
{
@@ -305,7 +305,7 @@ namespace Serein.Library.Utils
/// <summary>
/// 表达式树构建无参数,有返回值(Task<object>)的方法(触发器)
/// 表达式树构建无参数,有返回值(Task&lt;object&gt;)的方法(触发器)
/// </summary>
public static Delegate MethodCallerAsync(Type type, MethodInfo methodInfo)
{
@@ -314,7 +314,7 @@ namespace Serein.Library.Utils
}
/// <summary>
/// 表达式树构建无参数,有返回值(Task<object>)的方法(触发器)
/// 表达式树构建无参数,有返回值(Task&lt;object&gt;)的方法(触发器)
/// </summary>
/// <param name="type"></param>
/// <param name="methodInfo"></param>
@@ -332,7 +332,7 @@ namespace Serein.Library.Utils
/// <summary>
/// 表达式树构建多个参数,有返回值(Task-object)的方法(触发器)
/// 表达式树构建多个参数,有返回值(Task&lt;object&gt;)的方法(触发器)
/// </summary>
public static Delegate MethodCallerAsync(Type type, MethodInfo method, params Type[] parameterTypes)
{
@@ -342,7 +342,7 @@ namespace Serein.Library.Utils
}
/// <summary>
/// 表达式树构建多个参数,有返回值(Task<object>)的方法(触发器)
/// 表达式树构建多个参数,有返回值(Task&lt;object&gt;)的方法(触发器)
/// </summary>
private static Delegate CreateMethodCallerDelegateAsync(Type type, MethodInfo methodInfo, Type[] parameterTypes)
{
@@ -384,31 +384,12 @@ namespace Serein.Library.Utils
public static bool IsGenericTask(Type returnType, out Type taskResult)
{
// 判断是否为 Task 类型或泛型 Task<T>
if (returnType == typeof(Task))
{
taskResult = null;
return true;
}
else if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
{
// 获取泛型参数类型
Type genericArgument = returnType.GetGenericArguments()[0];
taskResult = genericArgument;
return true;
}
else
{
taskResult = null;
return false;
}
}
/// <summary>
/// / 自动创建一个委托,根据方法信息和类型
/// </summary>
/// <param name="type"></param>
/// <param name="methodInfo"></param>
/// <returns></returns>
public static Delegate AutoCreate(Type type, MethodInfo methodInfo)
{
Type returnType = methodInfo.ReturnType;

View File

@@ -9,6 +9,10 @@ using System.Threading.Tasks;
namespace Serein.Library.Utils
{
/// <summary>
/// 基于 Channel 的触发器实现
/// </summary>
/// <typeparam name="TSignal"></typeparam>
public class ChannelFlowTrigger<TSignal> : IFlowTrigger<TSignal>
{
// 使用并发字典管理每个枚举信号对应的 Channel
@@ -24,6 +28,13 @@ namespace Serein.Library.Utils
return _channels.GetOrAdd(signal, _ => Channel.CreateUnbounded<TriggerResult<object>>());
}
/// <summary>
/// 等待信号触发并指定超时时间
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="signal"></param>
/// <param name="outTime"></param>
/// <returns></returns>
public async Task<TriggerResult<TResult>> WaitTriggerWithTimeoutAsync<TResult>(TSignal signal, TimeSpan outTime)
{
var channel = GetOrCreateChannel(signal);
@@ -54,6 +65,12 @@ namespace Serein.Library.Utils
}
/// <summary>
/// 等待信号触发
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="signal"></param>
/// <returns></returns>
public async Task<TriggerResult<TResult>> WaitTriggerAsync<TResult>(TSignal signal)
{
var channel = GetOrCreateChannel(signal);
@@ -76,6 +93,13 @@ namespace Serein.Library.Utils
}
}
/// <summary>
/// 调用触发器
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="signal"></param>
/// <param name="value"></param>
/// <returns></returns>
public async Task<bool> InvokeTriggerAsync<TResult>(TSignal signal, TResult value)
{
if (_channels.TryGetValue(signal, out var channel))
@@ -92,6 +116,9 @@ namespace Serein.Library.Utils
return false;
}
/// <summary>
/// 取消所有触发器
/// </summary>
public void CancelAllTrigger()
{
foreach (var channel in _channels.Values)

View File

@@ -141,13 +141,30 @@ namespace Serein.Library.Utils
{
private readonly Action<T> _onNext;
/// <summary>
/// 构造函数,接受一个 Action 作为回调
/// </summary>
/// <param name="onNext"></param>
public Observer(Action<T> onNext)
{
_onNext = onNext;
}
/// <summary>
/// 通知订阅者已完成或发生错误
/// </summary>
public void OnCompleted() { }
/// <summary>
/// 通知订阅者发生错误
/// </summary>
/// <param name="error"></param>
public void OnError(Exception error) { }
/// <summary>
/// 通知订阅者有新数据到来
/// </summary>
/// <param name="value"></param>
public void OnNext(T value)
{
_onNext?.Invoke(value);

View File

@@ -7,9 +7,20 @@ using System.Threading.Tasks;
namespace Serein.Library.Utils
{
/// <summary>
/// 触发器结果类,用于存储触发器的类型和返回值。
/// </summary>
/// <typeparam name="TResult"></typeparam>
public class TriggerResult<TResult>
{
/// <summary>
/// 触发类型
/// </summary>
public TriggerDescription Type { get; set; }
/// <summary>
/// 触发结果值
/// </summary>
public TResult Value { get; set; }
}
}

View File

@@ -23,28 +23,57 @@ namespace Serein.Library.Utils
JsonHelper.provider = jsonPortal;
}
/// <summary>
/// 反序列化Json文本为指定类型的对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="jsonText"></param>
/// <returns></returns>
public static T Deserialize<T>(string jsonText)
{
return provider.Deserialize<T>(jsonText);
}
/// <summary>
/// 反序列化Json文本为指定类型的对象
/// </summary>
/// <param name="jsonText"></param>
/// <param name="type"></param>
/// <returns></returns>
public static object Deserialize(string jsonText, Type type)
{
return provider.Deserialize(jsonText, type);
}
/// <summary>
/// 解析Json文本为IJsonToken对象
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
public static IJsonToken Parse(string json)
{
return provider.Parse(json);
}
/// <summary>
/// 将对象序列化为Json文本
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static string Serialize(object obj)
{
return provider.Serialize(obj);
}
/// <summary>
/// 创建一个Json对象使用字典初始化
/// </summary>
/// <param name="init"></param>
/// <returns></returns>
public static IJsonToken Object(Action<Dictionary<string, object>> init)
{
var dict = new Dictionary<string, object>();
@@ -52,11 +81,21 @@ namespace Serein.Library.Utils
return provider.CreateObject(dict);
}
/// <summary>
/// 创建一个Json对象使用字典初始化
/// </summary>
/// <param name="values"></param>
/// <returns></returns>
public static IJsonToken Array(IEnumerable<object> values)
{
return provider.CreateArray(values);
}
/// <summary>
/// 将对象转换为JsonToken
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static IJsonToken FromObject(object obj)
{
if (obj is System.Collections.IEnumerable && !(obj is string))

View File

@@ -32,6 +32,14 @@ namespace Serein.Library.Utils
}
}
/// <summary>
/// 异步选择器,返回一个新的集合,其中每个元素都是通过异步方法转换的结果。
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="source"></param>
/// <param name="method"></param>
/// <returns></returns>
public static async Task<IEnumerable<TResult>> SelectAsync<TSource, TResult>(this IEnumerable<TSource> source,
Func<TSource, Task<TResult>> method)
{
@@ -39,6 +47,15 @@ namespace Serein.Library.Utils
}
/// <summary>
/// 异步选择器,返回一个新的集合,其中每个元素都是通过异步方法转换的结果。
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="source"></param>
/// <param name="method"></param>
/// <param name="concurrency"></param>
/// <returns></returns>
public static async Task<IEnumerable<TResult>> SelectAsync<TSource, TResult>(this IEnumerable<TSource> source,
Func<TSource, Task<TResult>> method,
int concurrency = int.MaxValue)

View File

@@ -28,23 +28,39 @@ namespace Serein.Library.Utils
internal T Value;
}
// 不使用System。Func{T},因为. net 2.0没有该类型。
/// <summary>
/// 不使用System。Func{T},因为. net 2.0没有该类型。
/// </summary>
/// <returns></returns>
public delegate T Factory();
// 池对象的存储。第一个项存储在专用字段中,因为我们希望能够满足来自它的大多数请求。
/// <summary>
/// 池对象的存储。第一个项存储在专用字段中,因为我们希望能够满足来自它的大多数请求。
/// </summary>
private T _firstItem;
private readonly Element[] _items;
// 工厂在池的生命周期内被存储。只有当池需要扩展时,我们才调用它。
// 与“new T”相比Func为实现者提供了更多的灵活性并且比“new T”更快
/// <summary>
/// 工厂在池的生命周期内被存储。只有当池需要扩展时,我们才调用它
/// 与“new T”相比Func为实现者提供了更多的灵活性并且比“new T”更快。
/// </summary>
private readonly Factory _factory;
/// <summary>
/// 创建一个新的对象池实例,使用指定的工厂函数和默认大小(处理器核心数的两倍)。
/// </summary>
/// <param name="factory"></param>
public ObjectPool(Factory factory)
: this(factory, Environment.ProcessorCount * 2)
{
}
/// <summary>
/// 创建一个新的对象池实例,使用指定的工厂函数和指定的大小。
/// </summary>
/// <param name="factory"></param>
/// <param name="size"></param>
public ObjectPool(Factory factory, int size)
{
Debug.Assert(size >= 1);
@@ -52,6 +68,10 @@ namespace Serein.Library.Utils
_items = new Element[size - 1];
}
/// <summary>
/// 创建一个新的实例。
/// </summary>
/// <returns></returns>
private T CreateInstance()
{
T inst = _factory();
@@ -82,6 +102,10 @@ namespace Serein.Library.Utils
return inst;
}
/// <summary>
/// 慢速分配方法,当第一个元素不可用时调用。
/// </summary>
/// <returns></returns>
private T AllocateSlow()
{
Element[] items = _items;

View File

@@ -669,6 +669,12 @@ namespace Serein.Library.Utils
#region
/// <summary>
/// 运行一个方法方法的参数类型由IOC容器提供
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="action"></param>
/// <returns></returns>
public ISereinIOC Run<T>(Action<T> action)
{
var service = Get<T>();
@@ -676,6 +682,13 @@ namespace Serein.Library.Utils
return this;
}
/// <summary>
/// 运行一个方法方法的参数类型由IOC容器提供
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <param name="action"></param>
/// <returns></returns>
public ISereinIOC Run<T1, T2>(Action<T1, T2> action)
{
var service1 = Get<T1>();
@@ -685,6 +698,14 @@ namespace Serein.Library.Utils
return this;
}
/// <summary>
/// 运行一个方法方法的参数类型由IOC容器提供
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <typeparam name="T3"></typeparam>
/// <param name="action"></param>
/// <returns></returns>
public ISereinIOC Run<T1, T2, T3>(Action<T1, T2, T3> action)
{
var service1 = Get<T1>();
@@ -694,6 +715,15 @@ namespace Serein.Library.Utils
return this;
}
/// <summary>
/// 运行一个方法方法的参数类型由IOC容器提供
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <typeparam name="T3"></typeparam>
/// <typeparam name="T4"></typeparam>
/// <param name="action"></param>
/// <returns></returns>
public ISereinIOC Run<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action)
{
var service1 = Get<T1>();