Aore.Toolkit
1.0.0
dotnet add package Aore.Toolkit --version 1.0.0
NuGet\Install-Package Aore.Toolkit -Version 1.0.0
<PackageReference Include="Aore.Toolkit" Version="1.0.0" />
<PackageVersion Include="Aore.Toolkit" Version="1.0.0" />
<PackageReference Include="Aore.Toolkit" />
paket add Aore.Toolkit --version 1.0.0
#r "nuget: Aore.Toolkit, 1.0.0"
#:package Aore.Toolkit@1.0.0
#addin nuget:?package=Aore.Toolkit&version=1.0.0
#tool nuget:?package=Aore.Toolkit&version=1.0.0
Aore.Toolkit
零依赖的 .NET 通用工具库:面向「函数处理 + 集合操作」,覆盖函数处理管线(防抖、节流、记忆化缓存、重试、限流、熔断器)、对象池、带缓存反射、线程安全单例、迭代器与双向链表 / 列表 / 队列 / 堆栈等集合工具。
- 零 NuGet 依赖:核心库不引用任何第三方包,算法、反射加速、并发原语一律本地实现。
- 7 个目标框架:netstandard2.0 / net462 / net472 / net48 / net8.0 / net9.0 / net10.0。
- 生产就绪基线:0 错误 0 警告编译、单元测试覆盖 net48 + net8.0、中文 XML 注释(IntelliSense 友好)。
本文档是 NuGet 包内嵌说明文档(
PackageReadmeFile),每次新增模块后请同步更新本文档的「能力清单」「API 方法清单」「API 完整使用方法」与「注意事项」。
能力清单
| 命名空间 | 能力 |
|---|---|
Aore.Toolkit.Pooling |
ObjectPool<T> 通用对象池、共享池门面 |
Aore.Toolkit.Reflection |
ReflectionCache 带缓存反射工具、ReflectionExtensions |
Aore.Toolkit.Patterns |
SingletonBase<T> 单例基类、Singleton<T> 普通泛型单例 |
Aore.Toolkit.Collections |
Iterator 迭代器工具类、IIterator<T> / EnumerableIterator<T> 迭代器模式游标、DoublyLinkedList<T> 双向链表、ListExtensions 列表扩展、QueueExtensions / Deque<T> 队列工具、StackExtensions / MinMaxStack<T> 堆栈工具 |
Aore.Toolkit.Functions |
FuncExtensions 函数处理方法、Debouncer 防抖、Throttle 节流、Memoizer<TKey, TValue> 函数缓存(记忆化) |
Aore.Toolkit.Resilience |
IClock 时间源、IRateLimiter 限流(令牌桶 / 固定窗口 / 滑动窗口 / 并发限制)、CircuitBreaker 熔断器、CircuitBreakerRegistry 命名注册表 |
安装
dotnet add package Aore.Toolkit
或从源码引用:将 src/Aore.Toolkit 工程作为项目引用加入解决方案。
快速上手
using Aore.Toolkit.Pooling;
using Aore.Toolkit.Reflection;
using Aore.Toolkit.Collections;
using Aore.Toolkit.Functions;
using Aore.Toolkit.Resilience;
// 迭代器工具:惰性序列 + 迭代器模式游标
Iterator.Range(1, 3); // 1, 2, 3(惰性)
Iterator.Window(items, 3); // 滑动窗口
var cursor = Iterator.Create(items); // 可重置读游标
// 双向链表:任意位置 O(1) 插入 / 移动(LRU 核心结构)
var order = new DoublyLinkedList<string>();
order.MoveToFront("A");
// 通用对象池:复用高频对象,减少内存分配
var sb = ObjectPool.StringBuilderPool.Rent();
try
{
sb.Append("Aore").Append('.');
// ...
}
finally
{
ObjectPool.StringBuilderPool.Return(sb); // 自动 Clear()
}
// 带缓存反射:命中后零反射分配
var getter = ReflectionCache.GetPropertyGetter(typeof(User), nameof(User.Name));
var userName = (string)getter(user);
// 函数缓存(记忆化):LRU + 命中率统计
var cache = ((Func<string, Type>)ResolveType).Memoize(capacity: 128);
cache.Get("User");
Console.WriteLine(cache.HitRate);
// 限流与熔断:保护下游
if (!bucket.TryAcquire()) { return TooManyRequests(); } // 令牌桶
var user = breaker.Execute(() => UserService.Get(1)); // 熔断保护
API 方法清单
ObjectPool(Aore.Toolkit.Pooling,通用对象池)
| 成员 | 签名摘要 | 说明 |
|---|---|---|
ObjectPool<T>.ctor |
(Func<T> factory, Action<T>? reset = null, int maxRetained = 32, int preRent = 0) |
工厂 + 复位回调 + 容量上限 + 预热 |
Rent |
() → T |
池内有则复用,否则调用工厂新建 |
Return |
(T obj) → void |
复位后入池;池满则丢弃(null 静默忽略) |
Trim |
(int maxIdle) / () → void |
裁剪空闲对象;无参等价 Clear() |
Clear |
() → void |
丢弃全部空闲对象 |
RetainedCount / CreatedCount / PeakRetainedCount |
int / long / int |
空闲数 / 累计创建数 / 空闲峰值(命中率调优依据) |
ObjectPool.For<T> |
() / (Func<T>) → IObjectPool<T> |
取(或创建)类型 T 的全局共享池,同一 T 唯一 |
ObjectPool.StringBuilderPool |
→ IObjectPool<StringBuilder> |
内置 StringBuilder 池,归还自动 Clear() |
ObjectPool.ClearSharedPools |
() → void / (Type) → void |
丢弃全部共享池的空闲对象;Type 重载按类型清理 |
ObjectPool.RemoveShared<T> |
() / (Type) → bool |
移除共享池(池退场并丢弃空闲对象);退场后 For<T> 重建全新池 |
ReflectionCache(Aore.Toolkit.Reflection,带缓存反射工具)
| 方法 | 签名摘要 | 说明 |
|---|---|---|
GetProperty / GetProperties |
(Type, string) → PropertyInfo? / (Type) → IReadOnlyList<PropertyInfo> |
缓存属性查找(含基类 public 与非 public) |
GetField |
(Type, string) → FieldInfo? |
缓存字段查找 |
GetMethod |
(Type, string, Type?[]? = null) → MethodInfo? |
按参数签名查找,重载歧义抛 AmbiguousMatchException |
GetMethod |
(Type, string, int parameterCount) → MethodInfo? |
按参数个数查找 |
GetConstructor |
(Type, Type?[]? = null) → ConstructorInfo? |
按参数签名查找构造 |
GetNestedType |
(Type, string) → Type? |
缓存嵌套类型查找 |
GetGenericArguments / GetGenericArgument |
(Type) → Type[] / (Type, int) → Type? |
缓存泛型实参 |
GetElementType / TryGetElementType |
(Type) → Type? / (Type, out Type) → bool |
解包数组与常见泛型容器接口(IEnumerable<T> / ICollection<T> / Task<T> 等) |
IsNullable / GetUnderlyingType |
(Type) → bool / (Type) → Type? |
可空判定与 Nullable<T> 解包 |
GetDefaultValue |
(Type) → object? |
缓存的类型默认值 |
GetPropertyGetter / GetPropertySetter |
(Type, string) → Func<object, object?> / Action<object, object?>? |
缓存的表达式树编译访问器(只读属性 setter 返回 null) |
GetValue / SetValue |
(object, string) → object? / (object, string, object?) → void |
走缓存委托的读写快捷方式 |
CacheCount / Clear |
int / () → void |
缓存条目数(诊断)/ 清空缓存 |
Clear |
(Type) → int |
按类型精准清除全部相关条目(插件卸载 / ALC 场景),返回移除条目数 |
HighWaterMark / TrimmedTypeCount |
int / long |
条目总数预警水位(软上限,默认 0 = 关闭)/ 累计驱逐 Type 数(诊断) |
ReflectionExtensions |
GetPropertyValue / SetPropertyValue / FindMethod / FindProperty / FindField |
扩展方法形态的链式封装 |
单例(Aore.Toolkit.Patterns)
| 成员 | 签名摘要 | 说明 |
|---|---|---|
SingletonBase<T>.Instance |
→ T |
线程安全惰性单例(LazyThreadSafetyMode.ExecutionAndPublication) |
SingletonBase<T>.IsCreated |
→ bool |
是否已构造(不触发构造) |
SingletonBase<T>.OnSingletonCreated |
protected virtual void |
子类一次性初始化钩子 |
SingletonBase<T>.DisposeInstance |
() → void |
释放并丢弃实例(释放资源) |
SingletonBase<T>.Reset |
() → void |
丢弃实例引用,仅供单元测试 |
Singleton<T>.Instance / IsCreated / Reset |
同上(无需继承) | 普通泛型单例 |
Iterator / EnumerableIterator(Aore.Toolkit.Collections,迭代器)
| 方法 | 签名摘要 | 说明 |
|---|---|---|
Empty<T> |
() → IEnumerable<T> |
空序列(共享单例,零分配) |
Repeat<T> |
(T value, int count) → IEnumerable<T> |
重复值 count 次(惰性) |
Repeat<T> |
(T value) → IEnumerable<T> |
无限重复同一值 |
RepeatSequence<T> |
(IEnumerable<T> source, int count) → IEnumerable<T> |
整段重复数据源 |
Range |
(int start, int count) → IEnumerable<int> |
连续整数(溢出前置检查) |
Range |
(int start, int end, int step) → IEnumerable<int> |
按步进区间;方向不匹配返回空 |
Cycle<T> |
(IEnumerable<T> source) → IEnumerable<T> |
无限循环枚举 |
Batch<T> |
(IEnumerable<T>, int size) → IEnumerable<IReadOnlyList<T>> |
不重叠分块,末块可短 |
Window<T> |
(IEnumerable<T>, int size) → IEnumerable<IReadOnlyList<T>> |
滑动窗口 |
Create<T> |
(IEnumerable<T> source) → IIterator<T> |
创建可重置读游标 |
IIterator<T> |
MoveNext / Current / HasNext / Position / Reset |
迭代器模式:HasNext 不推进游标 |
EnumerableIterator<T>.Dispose |
() → void |
释放底层枚举器(同时是 IEnumerator<T> / IEnumerable<T>) |
DoublyLinkedList(Aore.Toolkit.Collections,双向链表)
| 成员 | 签名摘要 | 说明 |
|---|---|---|
| 构造 | () / (int capacity) / (IEnumerable<T>) |
空表 / 预留容量 / 由序列创建 |
Count / First / Last |
int / DoublyLinkedListNode<T>? |
元素数 / 首节点 / 尾节点(空为 null) |
FirstNode / LastNode |
DoublyLinkedListNode<T> |
空链表抛 InvalidOperationException |
AddFirst / AddLast / Add |
(T) → DoublyLinkedListNode<T> |
头 / 尾插入并返回新节点 |
AddAfter / AddBefore |
(node, T) → void |
指定节点后 / 前插入(O(1)) |
| 索引器 | this[node] |
按节点读写 Value |
Remove |
(T) → bool / (node) → bool |
按值 / 按节点删除;删除后节点导航清空 |
RemoveFirst / RemoveLast |
() → void |
删除首 / 尾节点(空表抛异常) |
Find / Contains / ForEach |
(T) → node? / (T) → bool / (Action<T>) |
查找 / 判定 / 正向遍历 |
MoveToFirst / MoveToLast / MoveAfter / MoveBefore |
(node[, reference]) → void |
O(1) 移动节点(保持同一节点实例) |
Reverse / Clear / ToArray |
() → ... |
原地反转 / 清空 / 导出数组 |
CopyTo |
(T[], int) / (node[], int) |
复制元素 / 节点 |
RemoveWhere / FindFirst / FindLast |
(Predicate<T>) → int / node? |
按谓词批量删除与定位 |
InsertAfter / InsertBefore |
(value, referenceValue) → node |
按值定位参考节点后插入(找不到则追加到尾部) |
MoveToFront / MoveToBack |
(value) → bool |
LRU 两行搞定 |
ForEachBackward / ToDoublyLinkedList |
(Action<T>) / 静态 |
反向遍历 / 序列转链表 |
ListExtensions(Aore.Toolkit.Collections,列表操作与扩展)
| 方法 | 签名摘要 | 说明 |
|---|---|---|
AddRange |
(this IList, IEnumerable) → void |
非泛型列表批量追加 |
InsertRange / ReplaceRange |
(this IList<T>, int, IEnumerable<T>) → void |
区间插入 / 区间覆盖(不足则截断、更多则扩容) |
GetRange |
(this IList<T>, int, int) → List<T> |
导出区间副本(异常语义与 List<T>.GetRange 一致) |
RemoveWhere / IndexOf |
(this IList<T>, Func<T, bool>) → int |
谓词批量删除 / 定位下标 |
RemoveFirst / RemoveLast |
(this IList<T>, Func<T, bool>) → bool |
删除首个 / 末个匹配项 |
Swap |
(this IList<T>, int, int) → void |
交换两元素 |
ReverseInPlace |
(this IList<T>) → void |
接口化原地反转 |
ShuffleInPlace / Shuffled |
(this IList<T>, Random?) → void / List<T> |
Fisher-Yates 洗牌 / 洗牌副本 |
Chunk |
(this IList<T>, int) → IEnumerable<IReadOnlyList<T>> |
定长分块(惰性) |
At / IsInRange |
(this IList<T>, int) → T / bool |
安全取值(越界返回 default)/ 索引校验 |
Fill |
(this IList<T>, T, int, int) → void |
区间填充 |
TryEnsureCapacity |
(this List<T>, int) → bool |
容量不足时扩容,返回是否扩容 |
BinarySearchIndex |
(this IList<T>, T, IComparer<T>?) → int |
二分查找(未命中返回按位补码插入点) |
AddIf / AddIfNotNull |
(this IList<T>, bool, T) / (this IList<T>, T?) |
条件 / 非空才追加 |
QueueExtensions / Deque(Aore.Toolkit.Collections,队列工具)
| 方法 | 签名摘要 | 说明 |
|---|---|---|
EnqueueRange / EnqueueIf / EnqueueIfNotNull |
(this Queue<T>, …) → void |
批量 / 条件 / 非空入队 |
DequeueRange |
(this Queue<T>, int) → List<T> |
批量出队(不足则取尽) |
DequeueWhile |
(this Queue<T>, Func<T, bool>) → int |
按谓词出队(只 Peek,保留剩余顺序) |
DequeueAll |
(this Queue<T>) → T[] |
一次性排空 |
Deque<T> |
PushFront / PushBack / PopFront / PopBack |
双端队列(环形数组,摊还 O(1)) |
Deque<T> Try 系列 |
TryPopFront / TryPopBack / TryPeekFront / TryPeekBack |
空队列返回 false |
Deque<T> |
Count / IsEmpty / Clear / TrimExcess / ToArray |
常规操作 |
StackExtensions / MinMaxStack(Aore.Toolkit.Collections,堆栈工具)
| 方法 | 签名摘要 | 说明 |
|---|---|---|
PushRange |
(this Stack<T>, IEnumerable<T>) → void |
批量压栈(栈顶为源末元素) |
PopRange / PopWhile / PopAll |
(this Stack<T>, …) → List<T> / int / T[] |
批量弹出 / 按谓词弹出 / 排空 |
TryPop |
(this Stack<T>, out T) → bool |
安全弹栈(net6+ 由 BCL 同名实例方法提供,语义一致) |
MinMaxStack<T> |
(IComparer<T>?) / Push / Pop / Peek / TryPop |
栈基础操作 |
MinMaxStack<T> |
GetMin / GetMax / TryGetMin / TryGetMax |
O(1) 最小 / 最大值查询 |
FuncExtensions(Aore.Toolkit.Functions,函数处理相关方法)
| 方法 | 签名摘要 | 说明 |
|---|---|---|
TryInvoke / TryInvoke\<T\> |
(this Action, out Exception?) → bool / (this Func<T>, out T?, out Exception?) → bool |
安全调用并捕获可恢复异常(致命异常不吞) |
InvokeSafely |
(this Action, Action<Exception>? onError = null) → void |
事件回调场景:异常交给 onError 或吞掉 |
InvokeOrDefault |
(this Func<T>, T fallback, Action<Exception>? onError = null) → T |
异常时返回兜底值 |
InvokeIf |
(this Action, bool) → void / (this Func<T>, bool, T) → T |
条件成立才执行 |
InvokeWithTimeout |
(this Action, TimeSpan) → void / (this Func<T>, TimeSpan, T) → T |
限时等待;超时抛 TimeoutException / 返回兜底值;无法终止已启动工作 |
Retry / Retry\<T\> |
(this Action / Func<T>, int maxAttempts = 3, TimeSpan? delay = null, Func<Exception,bool>? shouldRetry = null) |
同步重试,耗尽重抛最后异常 |
RetryAsync / RetryAsync\<T\> |
(this Func<Task> / Func<Task<T>>, …, CancellationToken = default) |
异步重试 |
Compose |
(this Func<T1,T2>, Func<T2,TResult>) → Func<T1,TResult> |
函数组合 x => second(first(x)) |
MemoizeOnce |
(this Func<T>) → Func<T> |
无参工厂的单键记忆化(Lazy<T> 单飞,异常也缓存) |
Debouncer / Throttle(Aore.Toolkit.Functions,防抖与节流)
| 成员 | 签名摘要 | 说明 |
|---|---|---|
Debouncer |
(Action action, TimeSpan delay, Action<Exception>? onError = null) |
防抖:静默期内连续触发只执行最后一次 |
Debouncer |
Invoke() / Flush() → bool / Cancel() / IsPending / Delay / Dispose() |
Flush 立即执行并返回 true |
ThrottleMode |
enum { Leading, Trailing, LeadingAndTrailing } |
触发模式 |
Throttle |
(Action action, TimeSpan interval, ThrottleMode mode = Leading, Action<Exception>? onError = null) |
节流:窗口内最多执行一次 |
Throttle |
Invoke() → bool / Cancel() / Interval / Mode / Dispose() |
Invoke 返回本次是否真的执行 |
Memoizer(Aore.Toolkit.Functions,函数缓存 / 记忆化)
| 成员 | 签名摘要 | 说明 |
|---|---|---|
Memoizer<TKey,TValue> |
(Func<TKey,TValue> factory, int capacity = 128, IEqualityComparer<TKey>? = null, TimeSpan? ttl = null, Func<TKey,TValue,TimeSpan>? ttlSelector = null, IClock? = null) |
线程安全 LRU 缓存;ttl / ttlSelector 启用惰性过期(默认永不过期) |
Memoizer |
Get(key) → TValue |
命中刷新 LRU;未命中计算后写入(工厂异常原样透传且不缓存) |
Memoizer |
TryGet(key, out TValue?) → bool / ContainsKey(key) |
只读缓存,不触发工厂 |
Memoizer |
Invalidate(key) → bool / Clear() |
失效 / 清空 |
Memoizer |
Capacity / Count / Hits / Misses / HitRate |
容量与命中率统计 |
Memoize |
(this Func<TKey,TValue>, int capacity = 128, …) → Memoizer<TKey,TValue> |
得到可管理缓存对象 |
Memoized |
(this Func<TKey,TValue>, …) → Func<TKey,TValue> |
得到替换后的委托(用法最简洁) |
IClock(Aore.Toolkit.Resilience,时间源)
| 成员 | 签名摘要 | 说明 |
|---|---|---|
IClock.ElapsedMilliseconds |
long |
进程内单调递增毫秒数 |
SystemClock.Instance |
static |
基于 Stopwatch 的系统时钟单例(不回绕) |
ManualClock |
(long startMilliseconds = 0) / Advance(...) / SetTo(...) |
手动推进时钟,用于确定性测试(时间不可倒流) |
Timing(Aore.Toolkit.Timing,时间与调度)
| 成员 | 签名摘要 | 说明 |
|---|---|---|
ValueStopwatch.StartNew / CreateStopped |
static → ValueStopwatch |
struct 零分配计时器;复制即独立快照 |
ValueStopwatch |
Start / Stop / Restart / Reset / IsRunning |
暂停累计 / 幂等;Restart 全 TFM 可用(ns2.0 补齐) |
ValueStopwatch 读数 |
ElapsedNanoseconds / ElapsedMicroseconds / ElapsedMilliseconds / Elapsed / ElapsedTicks |
纳秒级整数读数(分段换算防溢出);毫秒为截断语义 |
ValueStopwatch.Lap / CreateSnapshot |
() → TimeSpan / → StopwatchSnapshot |
计圈(不重置总累计)/ 只读快照 |
Monotonic.GetTimestamp / GetElapsedTime |
() → long / (start[, end]) → TimeSpan |
单调时间戳与耗时回传(.NET 7+ API 下放全 TFM) |
Monotonic.TimestampToNanoseconds / NanosecondsToTicks |
(long) → long |
刻度 ↔ 纳秒(「整秒 + 余数」分段换算,无中间溢出) |
Monotonic.Frequency / Resolution / IsHighResolution |
long / TimeSpan / bool |
频率 / 单刻度时长(100ns 粒度量化)/ 高分辨率感知 |
Monotonic.Measure / MeasureAsync |
(Action) → TimeSpan / (Func<Task>) → Task<TimeSpan> |
同步 / 异步作用域测量 |
MonotonicDeadline.FromNow |
static (TimeSpan budget) → MonotonicDeadline |
单调截止预算(readonly struct,可共享) |
MonotonicDeadline |
IsExpired / Remaining / RemainingMilliseconds / ThrowIfExpired() |
到期判定;剩余归零不取负;到期抛 TimeoutException |
ScheduleMode |
enum { FixedDelay, FixedRate } |
FixedDelay 防重叠;FixedRate 防漂移(错过节拍跳过不补发) |
ScheduleTimer 构造 |
(Func<CancellationToken,Task> / (Action, TimeSpan interval, ScheduleMode, ScheduleOptions?) |
构造即启动;回调永不重叠;异常交给 OnError 绝不击穿进程 |
ScheduleTimer.ScheduleOnce |
static (Action, TimeSpan dueIn, Action<Exception>?) → ScheduleTimer |
一次性延迟执行,完成后自动停止 |
ScheduleTimer 控制 |
Pause() / Resume() / Dispose() |
暂停保留节拍基准;Dispose 幂等不抛并取消在途回调令牌 |
ScheduleTimer 诊断 |
ExecutionCount / ErrorCount / SkippedCount / IsRunning / IsPaused |
Interlocked 计数 |
ScheduleTimer.WaitForNextTickAsync |
(CancellationToken = default) → Task<bool> |
PeriodicTimer 风格 awaitable(全 TFM);Dispose 后返回 false |
ScheduleOptions |
MaxExecutions(0=无限) / OnError / OnCompleted / Name |
配置对象(创建后勿改) |
IRateLimiter(Aore.Toolkit.Resilience,限流机制)
| 成员 | 签名摘要 | 说明 |
|---|---|---|
RateLimiterAlgorithm |
enum { TokenBucket, FixedWindow, SlidingWindow, Concurrency } |
算法枚举 |
TryAcquire |
(int permits = 1) → bool |
尝试获取;限流失败只返回 false,绝不抛限流异常 |
WaitTimeFor |
(int permits = 1) → TimeSpan |
Zero = 当前可获得,否则为建议等待时长 |
Acquire |
(int permits = 1, TimeSpan? timeout = null) / (TimeSpan? timeout) |
阻塞等待;超时抛 TimeoutException |
WaitAsync |
(int permits = 1, CancellationToken = default) → Task<bool> |
异步等待 |
TotalAcquired / TotalRejected |
long |
累计放行 / 拒绝(Reset() 不清零) |
Reset |
() → void |
重置限流状态 |
Release(仅并发限制) |
(int permits = 1) → void |
归还并发许可(多还钳 0,不抛异常) |
RateLimitOptions |
Algorithm / Permits / Window / Clock |
配置对象 |
RateLimiterFactory.Create |
(RateLimitOptions) → IRateLimiter / (algorithm, permits, window, clock?) |
按算法创建 |
TokenBucketRateLimiter |
(int capacity, double permitsPerSecond, IClock? = null) |
令牌桶,允许突发;AvailableTokens 可查余额 |
FixedWindowRateLimiter |
(int limit, TimeSpan window, IClock? = null) |
固定窗口,开销最小;边界可 2 倍突发 |
SlidingWindowRateLimiter |
(int limit, TimeSpan window, IClock? = null) |
滑动窗口精确计数,边界平滑;CurrentCount 可查在窗数 |
ConcurrencyRateLimiter |
(int maxConcurrency, IClock? = null) |
并发在途上限;需配对 Release;Current 可查在途数 |
CircuitBreaker(Aore.Toolkit.Resilience,熔断器模式)
| 成员 | 签名摘要 | 说明 |
|---|---|---|
CircuitState |
enum { Closed, Open, HalfOpen } |
三态 |
CircuitBreakerOptions |
FailureThreshold(5) / BreakDuration(30s) / HalfOpenTrialCount(1) / SuccessThreshold(1) / OnStateChanged |
配置;Validate() 校验并返回自身 |
CircuitBreaker |
(CircuitBreakerOptions? = null, IClock? = null) |
熔断器;不含重试(重试会放大下游压力) |
State / Snapshot |
CircuitState / CircuitBreakerSnapshot |
状态(读取不触发迁移,判定以 TryAcquire 为准)/ 指标快照 |
TryAcquire / ReportSuccess / ReportFailure |
() → bool / () → void / () → void |
手动模式 |
Execute / ExecuteAsync |
(Action) / (Func<T>) → T / (Func<Task>) / (Func<Task<T>>) → Task<T> |
自动模式;熔断打开时抛 CircuitOpenException |
Reset |
() → void |
强制闭合并清零全部计数 |
CircuitOpenException |
(string, CircuitState, TimeSpan? retryAfter) |
快速失败异常(继承 Exception,携带 State / RetryAfter) |
CircuitBreakerSnapshot |
State / TimeInCurrentState / TotalCalls / TotalSuccesses / TotalFailures / ConsecutiveFailures / ConsecutiveSuccesses / RejectedCalls / RetryAfter |
只读结构体快照 |
CircuitBreakerRegistry |
Get(name) / TryGet / All / Count / ResetAll / Remove(name) / Clear() / MaxBreakers |
按下游隔离状态;同名恒同一实例;Remove / Clear 手动回收条目;MaxBreakers 容量软上限(超限按创建序只淘汰 Closed 态,默认 0 = 不限制) |
集合选型速查
| 需求 | 选择 |
|---|---|
| 高频耗时统计(零分配、亚毫秒精度) | ValueStopwatch(struct) |
| 跨 await 的超时预算检查 | MonotonicDeadline |
| 时间戳差值 / 高精度换算 / 作用域测量 | Monotonic.GetElapsedTime / Measure |
| 周期任务防重叠(回调耗时不定) | ScheduleTimer(FixedDelay) |
| 周期任务防漂移(错过节拍跳过不补发) | ScheduleTimer(FixedRate) |
| 一次性延迟执行 | ScheduleTimer.ScheduleOnce |
| 任意位置 O(1) 插入删除 + 持有节点引用(LRU / 撤销栈) | DoublyLinkedList<T> |
| 两端插入删除 | Deque<T>(或 Queue<T> + 本库扩展) |
| 栈内最值 | MinMaxStack<T> |
只有 IList<T> 接口、需要批量 / 原地操作 |
ListExtensions |
| 高频事件合并(输入联想 / 自动保存) | Debouncer |
| 高频事件限速(滚动 / 鼠标移动) | Throttle |
| 昂贵函数结果复用 | Memoizer<TKey, TValue>(按 key)或 MemoizeOnce(无参) |
| 限制下游请求速率(允许突发) | TokenBucketRateLimiter |
| 平滑限速 / 计数最简 | SlidingWindowRateLimiter / FixedWindowRateLimiter |
| 限制同时在途请求数 | ConcurrencyRateLimiter |
| 下游故障时快速失败 | CircuitBreaker(可经 CircuitBreakerRegistry 按下游隔离) |
API 完整使用方法
ObjectPool(通用对象池)
// 1) 内置 StringBuilder 池(归还时自动 Clear)
var sb = ObjectPool.StringBuilderPool.Rent();
try
{
sb.Append("Aore.Toolkit");
}
finally
{
ObjectPool.StringBuilderPool.Return(sb);
}
// 2) 自定义池:工厂 + 复位回调 + 容量上限 + 预热
var pool = new ObjectPool<List<string>>(
() => new List<string>(16), // 工厂
list => list.Clear(), // 复位回调
maxRetained: 64,
preRent: 8); // 预热 8 个(受 maxRetained 约束)
var list = pool.Rent();
list.Add("x");
pool.Return(list); // 复位后入池
// 3) 全局共享池:同一 T 只有一个池实例
var shared = ObjectPool.For<MemoryStream>();
ObjectPool.ClearSharedPools(); // 内存压力回落 / 测试隔离
ReflectionCache(带缓存反射)
// 元数据查找(命中后不再触发反射)
var prop = ReflectionCache.GetProperty(typeof(User), nameof(User.Name)); // 不存在返回 null
var method = ReflectionCache.GetMethod(typeof(User), nameof(User.Save), new[] { typeof(string) });
var element = ReflectionCache.GetElementType(typeof(List<int>)); // int
ReflectionCache.GetDefaultValue(typeof(DateTime)); // 0001-01-01
// 缓存的读写委托(表达式树编译,命中后接近字段访问速度)
var getter = ReflectionCache.GetPropertyGetter(typeof(User), nameof(User.Name));
var setter = ReflectionCache.GetPropertySetter(typeof(User), nameof(User.Name));
var user = new User();
setter!(user, "Aore");
string? name = (string?)getter(user);
// 链式扩展方法形态
user.SetPropertyValue(nameof(User.Name), "Willis");
var value = user.GetPropertyValue(nameof(User.Name));
// 只读属性 / 缺失成员
ReflectionCache.GetPropertySetter(typeof(User), nameof(User.Id)); // null(只读)
ReflectionCache.GetPropertyGetter(typeof(User), "NotExist"); // 抛 MissingMemberException
ReflectionCache.Clear(); // 清空进程级缓存
// 插件卸载 / Collectible ALC:按类型精准清除,防止程序集被缓存条目钉住
ReflectionCache.Clear(typeof(User));
// 可选:启用条目总数预警水位(软上限,越线按 Type FIFO 自动驱逐最旧类型;默认 0 = 关闭)
ReflectionCache.HighWaterMark = 50_000;
单例
// 继承式单例基类(推荐:可加初始化钩子与释放逻辑)
public sealed class AppConfig : SingletonBase<AppConfig>
{
public string Endpoint { get; private set; } = "https://default";
protected override void OnSingletonCreated() => Endpoint = Environment.GetEnvironmentVariable("ENDPOINT") ?? Endpoint;
}
var config = AppConfig.Instance;
// 普通泛型单例(无需继承)
var helper = Singleton<JsonHelper>.Instance;
Iterator / EnumerableIterator(迭代器)
// 惰性序列
Iterator.Empty<int>(); // 空序列(零分配共享单例)
Iterator.Repeat("A", 3); // A A A
Iterator.RepeatSequence(new[] { 1, 2 }, 2); // 1 2 1 2
Iterator.Range(1, 3); // 1 2 3
Iterator.Range(10, 0, -2); // 10 8 6
Iterator.Range(0, 10, -1); // 空(方向不匹配,不死循环)
Iterator.Range(int.MaxValue, 2); // 抛 ArgumentOutOfRangeException
Iterator.Batch(new[] { 1, 2, 3, 4, 5 }, 2); // [1,2] [3,4] [5]
Iterator.Window(new[] { 1, 2, 3 }, 2); // [1,2] [2,3]
// 无限序列需自行截断
Iterator.Repeat(1).Take(3); // 1 1 1
Iterator.Cycle(new[] { 1, 2 }).Take(3); // 1 2 1
// 迭代器模式游标:HasNext 不推进位置
var cursor = Iterator.Create(new[] { 1, 2, 3 });
cursor.HasNext; // true(位置仍为 0)
while (cursor.MoveNext())
{
var item = cursor.Current;
}
cursor.Position; // 3
cursor.Reset(); // 可重复遍历
// 游标同时是 IEnumerable<T>,可直接接 LINQ
var even = ((EnumerableIterator<int>)Iterator.Create(Enumerable.Range(1, 5))).Where(x => x % 2 == 0);
DoublyLinkedList(双向链表)
using Aore.Toolkit.Collections;
// 头尾插入,节点可被外部持有
var list = new DoublyLinkedList<string>();
var node = list.AddLast("B");
list.AddFirst("A");
list.AddAfter(node, "C"); // A, B, C
list[node] = "BB"; // 按节点读写:A, BB, C
// 任意位置 O(1) 移动(保持同一节点实例,外部引用不失效)
list.MoveToFirst(node); // BB, A, C
list.MoveBefore(node, list.Last!); // A, BB, C
// 遍历(含反向)
list.ForEach(x => Console.WriteLine(x));
list.ForEachBackward(x => Console.WriteLine(x)); // C, BB, A
// 节点移出后导航清空,避免悬挂引用
list.Remove(node);
Console.WriteLine(node.List); // null
Console.WriteLine(node.Previous); // null
LRU 缓存(双向链表 + 字典,两行核心逻辑)
var order = new DoublyLinkedList<string>(); // 最近使用在前
var store = new Dictionary<string, byte>();
void Touch(string key)
{
if (store.ContainsKey(key))
{
order.MoveToFront(key); // 命中 → 提到最前
}
else
{
store[key] = 0;
order.MoveToBack(key); // 新增 → 放到最后(最旧)
if (order.Count > 3) // 超容量 → 淘汰最旧
{
var oldest = order.Last!.Value;
order.RemoveLast();
store.Remove(oldest);
}
}
}
ListExtensions(列表操作与扩展)
IList<int> numbers = new List<int> { 5, 3, 8, 1, 9, 2 };
numbers.RemoveWhere(x => x < 3); // 5, 8, 9, 2(返回删除数)
numbers.Swap(0, numbers.Count - 1); // 2, 8, 9, 5
numbers.ReverseInPlace(); // 5, 9, 8, 2
numbers.InsertRange(0, new[] { 0 }); // 0, 5, 9, 8, 2
numbers.ReplaceRange(1, new[] { 7, 8 }); // 0, 7, 8, 8, 2
numbers.Fill(-1, 1, 2); // 0, -1, -1, 8, 2
var blocks = numbers.Chunk(2); // 惰性分块
numbers.ShuffleInPlace(new Random(42)); // 原地洗牌(Fisher-Yates)
var sorted = numbers.Shuffled().OrderBy(x => x);
numbers.At(99); // 越界安全取值 → default(T) = 0
numbers.IsInRange(0); // true
numbers.TryEnsureCapacity(1024); // List<T> 专用,返回是否扩容
var sortedList = new List<int> { 1, 3, 5, 7 };
sortedList.BinarySearchIndex(5); // 2(命中)
sortedList.BinarySearchIndex(6); // 负数(~插入点)
QueueExtensions / Deque(队列工具)
var queue = new Queue<int>();
queue.EnqueueRange(new[] { 1, 2, 3, 4 }); // 批量入队
queue.DequeueWhile(x => x < 3); // 出队 1, 2(返回 2),剩余 3, 4
queue.DequeueRange(10); // 取尽 → [3, 4]
queue.DequeueAll(); // []
// 双端队列
var deque = new Deque<string>();
deque.PushBack("B");
deque.PushFront("A");
deque.PushBack("C");
deque.PeekFront(); // A
deque.PopBack(); // C
deque.TryPopBack(out var tail); // B → true(空时返回 false)
StackExtensions / MinMaxStack(堆栈工具)
var stack = new Stack<int>();
stack.PushRange(new[] { 1, 2, 3 }); // 栈顶为 3
stack.PopWhile(x => x > 2); // 弹出 3(返回 1)
stack.TryPop(out var top); // 2 → true
// O(1) 最值栈(滑动窗口最值场景)
var window = new MinMaxStack<int>();
foreach (var v in new[] { 4, 2, 9, 6 })
{
window.Push(v);
}
window.GetMin(); // 2
window.GetMax(); // 9
window.Pop();
window.GetMax(); // 6(自动回退)
// 自定义比较器(降序)
var desc = new MinMaxStack<int>(Comparer<int>.Create((x, y) => y.CompareTo(x)));
FuncExtensions(函数处理)
using Aore.Toolkit.Functions;
// 安全调用:捕获可恢复异常,OutOfMemory 等致命异常仍会抛出
if (!((Action)DoWork).TryInvoke(out var error))
{
Console.WriteLine(error!.Message);
}
// 事件回调:异常交给处理器,不向外抛
((Action)DoWork).InvokeSafely(ex => Console.WriteLine(ex.Message));
// 兜底取值 / 条件调用
Func<int> parse = () => throw new FormatException("bad");
int value = parse.InvokeOrDefault(-1);
parse.InvokeIf(false, -1); // -1(不执行 parse)
// 超时调用:超时抛 TimeoutException(返回值版本返回兜底值)
((Func<int>)SlowCall).InvokeWithTimeout(TimeSpan.FromSeconds(2), fallback: -1);
// 同步重试:第 3 次成功;耗尽后重抛最后一次异常
Func<string> call = () => RemoteGet();
var body = call.Retry(maxAttempts: 3, delay: TimeSpan.FromMilliseconds(200));
// 自定义重试条件:不可恢复的错误立即抛出
call.Retry(maxAttempts: 5, shouldRetry: ex => ex is TimeoutException);
// 异步重试(支持取消)
await ((Func<Task<string>>)RemoteGetAsync).RetryAsync(maxAttempts: 3, cancellationToken: ct);
// 函数组合
Func<string, string> mark = s => s + "?";
Func<string, int> length = s => s.Length;
Func<string, int> composed = mark.Compose(length); // s => (s + "?").Length
// 无参工厂的单键记忆化(异常也会被缓存)
var loadConfig = ((Func<string>)ReadConfigFile).MemoizeOnce();
Debouncer(防抖)
// 搜索框:连续输入只在停止 300ms 后请求一次
string keyword = string.Empty;
using var debouncer = new Debouncer(() => Search(keyword), TimeSpan.FromMilliseconds(300));
keyword = "aore"; debouncer.Invoke();
keyword = "aore t"; debouncer.Invoke(); // 计时被重置
// ... 300ms 后 Search 只被调用一次,keyword 已是最终值
debouncer.IsPending; // 是否有待执行动作
debouncer.Flush(); // 立即执行(返回 true),并取消后续定时触发
debouncer.Cancel(); // 放弃本次防抖
Throttle(节流)
// 滚动加载:100ms 内最多触发一次
int offset = 0;
using var throttle = new Throttle(() => LoadMore(offset), TimeSpan.FromMilliseconds(100));
throttle.Invoke(); // true(首次前导执行)
throttle.Invoke(); // false(窗口内被丢弃)
throttle.Invoke(); // false
// 后置模式:窗口结束才执行,适合埋点 / 自动保存
using var saver = new Throttle(() => Save(), TimeSpan.FromMilliseconds(500), ThrottleMode.Trailing);
saver.Invoke(); // false(不立即执行)
// 500ms 内多次调用只会在窗口结束时执行一次
Memoizer(函数缓存 / 记忆化)
// 得到可管理的缓存对象:查看命中率、失效、清空
Func<string, Type> resolve = name => AssemblyScan(name);
var cache = resolve.Memoize(capacity: 256);
cache.Get("User"); cache.Get("User");
Console.WriteLine(cache.HitRate); // 0.5
cache.Invalidate("User"); // 强制下次重算
cache.Clear();
// 简洁用法:直接拿到替换后的委托
Func<string, Type> cachedResolve = resolve.Memoized(capacity: 256);
// 自定义比较器(大小写不敏感)
var insensitive = resolve.Memoize(capacity: 256, StringComparer.OrdinalIgnoreCase);
// 带有效期:惰性过期(访问时判定,无后台线程);ttlSelector 可按 key / 值定制每项有效期
var expiring = resolve.Memoize(capacity: 256, ttl: TimeSpan.FromMinutes(5));
var perKey = resolve.Memoize(capacity: 256, ttlSelector: (key, _) => key.StartsWith("temp:") ? TimeSpan.FromSeconds(30) : TimeSpan.FromMinutes(10));
IClock(时间源,可确定性测试)
using Aore.Toolkit.Resilience;
// 系统时钟(默认)
IClock clock = SystemClock.Instance;
// 手动时钟:让所有「等一段时间」的场景变成纯逻辑断言,零 sleep、零偶发
var fake = new ManualClock();
var limiter = new FixedWindowRateLimiter(limit: 2, window: TimeSpan.FromSeconds(1), fake);
limiter.TryAcquire();
limiter.TryAcquire();
limiter.TryAcquire(); // false
fake.Advance(TimeSpan.FromSeconds(1));
limiter.TryAcquire(); // true(窗口已重置)
时间与调度(高精度计时 / 单调预算 / 调度定时器)
using Aore.Toolkit.Timing;
// 高精度计时器(struct 零分配,复制即独立快照):亚毫秒整数读数 + 全 TFM 可用的 Restart
var stopwatch = ValueStopwatch.StartNew();
DoWork();
stopwatch.Stop();
Console.WriteLine($"{stopwatch.ElapsedMilliseconds}ms / {stopwatch.ElapsedMicroseconds}µs");
stopwatch.Restart(); // 清零重新走表(ns2.0 也有)
// 时间戳差值与作用域测量(.NET 7+ GetElapsedTime 下放全 TFM)
var start = Monotonic.GetTimestamp();
await Task.Delay(100);
var elapsed = Monotonic.GetElapsedTime(start);
var measured = Monotonic.Measure(() => Thread.Sleep(50)); // 一行测耗时
// 单调截止预算:跨多次 await 的超时检查(与 CancellationTokenSource 墙钟超时互补)
var deadline = MonotonicDeadline.FromNow(TimeSpan.FromSeconds(5));
foreach (var item in items)
{
deadline.ThrowIfExpired(); // 到期抛 TimeoutException
await ProcessAsync(item);
}
// 调度定时器:回调永不重叠、异常不击穿进程、支持异步回调
using var timer = new ScheduleTimer(
async token => await HeartbeatAsync(token),
TimeSpan.FromSeconds(10), // FixedDelay:上次完成后隔 10s 再跑
options: new ScheduleOptions { Name = "heartbeat", OnError = ex => Log(ex) });
// 固定速率防漂移:错过节拍跳过不补发(SkippedCount 累计)
using var meter = new ScheduleTimer(PollAsync, TimeSpan.FromMilliseconds(250), ScheduleMode.FixedRate);
// 一次性延迟执行
var once = ScheduleTimer.ScheduleOnce(() => Console.WriteLine("40ms 后"), TimeSpan.FromMilliseconds(40));
// PeriodicTimer 风格的 awaitable 接口(全 TFM 可用)
while (await timer.WaitForNextTickAsync(cancellationToken))
{
await HandleTickAsync();
}
限流(4 种算法)
// 令牌桶:允许 capacity 突发,长期按 permitsPerSecond 均速
var bucket = new TokenBucketRateLimiter(capacity: 100, permitsPerSecond: 50);
if (!bucket.TryAcquire())
{
// 降级:返回缓存 / 排队 / 提示稍后重试
}
var wait = bucket.WaitTimeFor(); // 建议等待时长(Zero = 当前可获得)
// 固定窗口:开销最小,窗口边界可 2 倍突发
var fixedWindow = new FixedWindowRateLimiter(limit: 100, window: TimeSpan.FromSeconds(1));
// 滑动窗口:精确计数,边界平滑;内存 O(limit)
var sliding = new SlidingWindowRateLimiter(limit: 100, window: TimeSpan.FromSeconds(1));
// 并发限制:限制同时在途请求数
var slots = new ConcurrencyRateLimiter(maxConcurrency: 8);
if (slots.TryAcquire())
{
try
{
CallDownstream();
}
finally
{
slots.Release(); // 必须配对归还
}
}
// 阻塞 / 异步等待
bucket.Acquire(timeout: TimeSpan.FromSeconds(2)); // 超时抛 TimeoutException
await bucket.WaitAsync(cancellationToken: ct); // 异步等待
// 按配置统一创建
IRateLimiter limiter = RateLimiterFactory.Create(new RateLimitOptions
{
Algorithm = RateLimiterAlgorithm.TokenBucket,
Permits = 100,
Window = TimeSpan.FromSeconds(1),
});
熔断器(快速失败)
using Aore.Toolkit.Resilience;
var breaker = new CircuitBreaker(new CircuitBreakerOptions
{
FailureThreshold = 5, // 连续 5 次失败后打开
BreakDuration = TimeSpan.FromSeconds(30), // 打开持续 30s
HalfOpenTrialCount = 2, // 半开放行 2 个试探
SuccessThreshold = 2, // 成功 2 次后闭合
OnStateChanged = state => Metrics.Track("circuit", state), // 锁内同步,别做耗时操作
});
try
{
var user = breaker.Execute(() => UserService.Get(1)); // 自动上报
}
catch (CircuitOpenException ex)
{
// ex.State / ex.RetryAfter 告诉你「现在别打,稍后再来」
return Fallback();
}
catch (HttpRequestException ex)
{
// 业务异常原样透传,已计入失败
}
// 异步版:取消(OperationCanceledException)不计入失败
var user = await breaker.ExecuteAsync(() => UserService.GetAsync(1));
// 手动模式(自定义判定逻辑)
if (breaker.TryAcquire())
{
try
{
DoWork();
breaker.ReportSuccess();
}
catch
{
breaker.ReportFailure();
throw;
}
}
// 指标快照
var snap = breaker.Snapshot;
Console.WriteLine($"{snap.State} calls={snap.TotalCalls} fails={snap.TotalFailures} rejected={snap.RejectedCalls}");
// 按下游隔离状态
var registry = new CircuitBreakerRegistry(new CircuitBreakerOptions { FailureThreshold = 2 });
registry.Get("user-service").Execute(() => CallUserService());
registry.Get("order-service").Execute(() => CallOrderService());
// 容量软上限:超限按创建序只淘汰 Closed 态(Open / HalfOpen 与本次新建绝不淘汰);下游下线可手动移除
var bounded = new CircuitBreakerRegistry(new CircuitBreakerOptions { FailureThreshold = 2 }, maxBreakers: 32);
bounded.Remove("offline-service");
注意事项
null 约定:本库不提供公共参数校验与字符串扩展工具(模板示例模块已移除)。参数校验请直接使用
ArgumentNullException.ThrowIfNull(net6+)或手写if (x is null) throw new ArgumentNullException(nameof(x));;字符串判空请用string.IsNullOrWhiteSpace。本库各方法的 null 语义差异(null 安全 / 要求非 null)均在 XML 注释标注。异常约定:公共 API 优先抛标准异常(
ArgumentNullException/ArgumentException/ArgumentOutOfRangeException/MissingMemberException/AmbiguousMatchException/TimeoutException/InvalidOperationException),并尽量携带paramName;唯一专用异常是熔断快速失败的CircuitOpenException(携带State/RetryAfter)。对象池不释放实例:
Trim/Clear只丢弃不调用IDisposable.Dispose,池不擅自释放以避免二次释放;需要清理请放在复位回调中。对象池容量:
maxRetained = 0表示关闭池化(每次都新建);preRent会被maxRetained截断。命中率 = 1 -CreatedCount/ 租用总次数。反射缓存是进程级共享:
ReflectionCache.Clear()供动态程序集卸载 / 插件热重载 / 测试隔离使用;缓存持有Type引用,请勿在卸载场景下依赖默认行为。反射方法查找范围:
GetMethod依赖Type.GetMethods语义,可查到继承的 public / protected 方法,但不包含基类的 private 方法;属性与字段查找则显式遍历基类全链。Aore.Toolkit.Reflection命名空间与System.Reflection同名段:在该命名空间内请统一写using System.Reflection;并使用Type/MethodInfo等裸类型名,不要写Reflection.Xxx。单例
Reset()仅供测试:SingletonBase<T>.Reset()/Singleton<T>.Reset()会破坏单例语义(外部可能仍持有旧实例),生产代码禁止调用;释放资源请用DisposeInstance()。无限序列:
Iterator.Repeat(value)与Iterator.Cycle(source)返回无限序列,必须自行截断(例如Take(n)),否则foreach不会结束。游标线程安全:
EnumerableIterator<T>与 BCL 枚举器一致,非线程安全,请勿跨线程共享。集合容器线程安全:
DoublyLinkedList<T>/Deque<T>/MinMaxStack<T>均非线程安全(与 BCL 集合一致),需要并发安全请由调用方加锁。扩展方法同名遮蔽:部分扩展方法在 net6+ 会被同名 BCL 实例方法遮蔽(实例方法优先)——
GetRange/InsertRange/TryPop等。库内已对齐语义与异常类型;调用方若需明确指定,请用静态调用形式(如ListExtensions.TryPop(stack, out var v))。反向/原地语义:
ReverseInPlace/ShuffleInPlace/Shuffled(前者就地修改,后者返回副本)。超时不能中止:
InvokeWithTimeout只保证「调用方不再等待」,已启动的工作会继续在后台运行(异常会被观察,不会触发UnobservedTaskException)。需要真正中止请自行传入CancellationToken。定时器必须释放:
Debouncer/Throttle的Timer懒建但生命周期跟随实例,请用using/Dispose()释放;动作异常<b>默认被吞</b>,强烈建议传onError回调。记忆化与防抖的适用边界:
MemoizeOnce只适用于无参工厂(带参数请用Memoize/Memoized);Memoizer并发同 key 允许重复计算,工厂应无副作用;Retry的Thread.Sleep会阻塞调用线程,长耗时场景请用RetryAsync。目标框架:所有 API 在 7 个 TFM 上行为一致;垫片(
Compatibility/NullableAttributes.cs)保证旧框架下的可空注解编译,无运行时开销。net462 不内置ValueTuple,本库缓存键使用自定义结构体以保持零依赖。限流只返回 false:
TryAcquire被拒时不抛异常(避免异常风暴);只有Acquire在超时后才抛TimeoutException。permits大于限流器配额属配置错误,会一直拿不到许可。熔断器不含重试:
CircuitBreaker.Execute*不内置重试——熔断期间重试只会放大下游压力。重试用FuncExtensions.Retry*组合,且只对「非CircuitOpenException」重试。熔断状态是惰性迁移:
State读取本身不触发迁移,Open → HalfOpen的迁移发生在TryAcquire中,因此判定权威入口是TryAcquire。时间行为可测:限流与熔断的全部时间判定走
IClock,传入ManualClock即可在零 sleep的前提下确定性验证(库自身的测试即如此)。仅单进程生效:限流与熔断都是进程内状态,集群下每个实例各限各的;分布式场景需外部存储(属非目标)。
线程安全:无状态静态工具(
Iterator/ReflectionCache/FuncExtensions)天然线程安全;ObjectPool加锁、SingletonBase用Lazy<T>、Debouncer/Throttle/Memoizer/ 全部限流器 /CircuitBreaker/CircuitBreakerRegistry均为线程安全实现;集合容器与游标除外(见第 10 / 11 条)。内部类型不是公共 API:
Aore.Toolkit.Internal命名空间下的类型(如参数守卫)属实现细节,随版本可变更,不保证向后兼容。重试不重试取消异常:
Retry/Retry<T>/RetryAsync/RetryAsync<T>遇到OperationCanceledException(含TaskCanceledException)立即原样抛出,不消耗剩余重试次数;需重试取消场景请自行在shouldRetry之外处理。熔断中的取消不计成功也不计失败:
CircuitBreaker.ExecuteAsync*遇到OperationCanceledException只清零连续失败并原样抛出,不会被记为下游成功(避免InvokeWithTimeout产生的超时把熔断计数清零)。Acquire的超时是真实墙钟:IRateLimiter.Acquire(permits, timeout)的timeout由内部Stopwatch判定,不受注入的IClock影响(否则传入ManualClock会永不超时);单次等待时长仍由IClock决定。限流请求量不得超过配额:
SlidingWindowRateLimiter的WaitTimeFor(permits > Limit)/Acquire会抛ArgumentOutOfRangeException(该请求量本质不可满足,快速失败而非空转);其余限流器TryAcquire一律返回false不抛异常。CircuitBreaker.Execute重载选择:() => Foo()这类有返回值的表达式体 lambda 会按 C# 规则绑定到Execute<T>而非Execute(Action);需明确执行Action版本请写成Action act = () => Foo();。枚举器耗尽安全:全部 struct 枚举器(
DoublyLinkedList<T>.Enumerator/Deque<T>.Enumerator/MinMaxStack<T>.Enumerator)在未开始或已越界时Current返回default(T),不抛异常。ReflectionCache不适用于裁剪 / NativeAOT:属性 / 字段 / 方法在裁剪后可能被移除,GetProperty等会返回null、GetValue会抛MissingMemberException;Expression.Compile()在不支持动态代码的平台已自动降级为反射访问(性能下降但功能正确)。EnumerableIterator<T>双重身份:类型同时是游标(IIterator<T>)与序列(IEnumerable<T>)。作为序列枚举(foreach/ LINQ)时返回独立新游标,不会重置本实例的Position/Current。DoublyLinkedList<T>自定义比较器:如需非默认比较(如大小写不敏感),用new DoublyLinkedList<T>(source, comparer);Find/Remove(T)/Contains均按该比较器判定。SingletonBase<T>.Dispose()会重置单例:释放的正是当前单例实例时会原子丢弃缓存引用,下次Instance重新构造(等价于DisposeInstance())。缓存键空间由调用方控制:
ReflectionCache(按 Type / 成员)、ObjectPool共享池(按泛型实参)、CircuitBreakerRegistry(按名称)的条目随使用增长,键空间有限时收敛;以动态键(动态生成类型、per-user / per-request 命名)访问会导致条目无限增长。管控选型:手动清理是地基(ReflectionCache.Clear(type)/Registry.Remove(name)/Clear()/ObjectPool.RemoveShared<T>()),容量管控是无人运维场景的兜底(ReflectionCache.HighWaterMark/Registry的maxBreakers,均为默认关闭的软上限),TTL 只属于业务值缓存(Memoizer);本库不内置定时清扫线程。Collectible AssemblyLoadContext 卸载前先清缓存:
ReflectionCache条目持有Type/MemberInfo/ 编译委托引用,只要条目存在,可卸载程序集就被钉住无法卸载。插件卸载前调用ReflectionCache.Clear(pluginType)(或全量Clear());被清条目后续访问自动重反射,正确性不受影响。ObjectPool.RemoveShared(type)可同步退场插件创建的共享池。自动管控是软上限且有驱逐语义:
HighWaterMark越线按 Type 插入序 FIFO 驱逐(每 64 次访问摊销检查,被驱逐条目重新反射 + 重编译,一次性性能毛刺);maxBreakers超限按创建序只淘汰 Closed 态(Open / HalfOpen 与本次新建绝不淘汰,无可淘汰条目时暂时超限,被淘汰熔断器状态丢失、同名重建归零)。MemoizerTTL 语义:ttl(默认有效期)与ttlSelector(按 key / 值定制,优先于ttl)均缺省 = 永不过期(与旧版行为一致);惰性过期无后台线程——访问时按注入IClock的单调毫秒判定,过期条目视同不存在并顺带移除,Get重新计算并计入Misses;容量压力下优先淘汰已过期条目;有效期必须为正时间跨度,选择器返回非正抛ArgumentOutOfRangeException;测试注入ManualClock可零 sleep 确定性验证。Timing的刻度不是 TimeSpan 刻度:Monotonic.GetTimestamp/ValueStopwatch.ElapsedTicks为 Stopwatch 刻度(平台频率相关),跨度换算必须经由Monotonic.TimestampToNanoseconds/GetElapsedTime;ValueStopwatch为 struct——赋值 / 传参即独立快照(非引用共享);Monotonic.Resolution按 100ns 粒度量化(GHz 级计数器下为 1 tick 下限)。静态门面类名为Monotonic而非Timing(避开与命名空间同名)。ScheduleTimer的防重叠与防漂移:FixedDelay上次回调完成后再计间隔(推荐默认,天然防重叠);FixedRate按节拍点排程,回调未完成错过节拍时跳过不补发(SkippedCount累计,补发会造成突发风暴);回调(含 async)永不重叠;异常交给OnError(缺省吞掉并计ErrorCount)绝不击穿进程;间隔为亚毫秒时取 1ms 下限;全部节拍判定基于单调毫秒(无 49 天回绕)。Dispose幂等不抛(与Debouncer/Throttle的 ObjectDisposed 语义刻意不同)并取消在途回调令牌。WaitForNextTickAsync是多播语义:同一节拍唤醒当前全部等待者;节拍在「回调开始执行」与「跳过节拍」时发生(不以回调完成为准);未等到节拍的调用方不保留历史节拍;Dispose / 达到MaxExecutions后返回false结束循环。
支持框架:netstandard2.0、net462、net472、net48、net8.0、net9.0、net10.0。
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 is compatible. net463 was computed. net47 was computed. net471 was computed. net472 is compatible. net48 is compatible. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.6.2
- No dependencies.
-
.NETFramework 4.7.2
- No dependencies.
-
.NETFramework 4.8
- No dependencies.
-
.NETStandard 2.0
- No dependencies.
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 109 | 10/1/2026 |