using System.Diagnostics; using GFramework.Core.Abstractions.Events; using GFramework.Core.Abstractions.StateManagement; using GFramework.Core.Events; namespace GFramework.Core.StateManagement; /// /// 集中式状态容器的默认实现,用于统一管理复杂状态树的读取、归约和订阅通知。 /// 该类型定位于现有 BindableProperty 之上的可选能力,适合跨模块共享、需要统一变更入口、 /// 支持调试历史或需要中间件/诊断能力的状态场景,而不是替代所有简单字段级响应式属性。 /// /// 状态树的根状态类型。 public sealed class Store : IStore, IStoreDiagnostics { /// /// 当前 Store 使用的 action 匹配策略。 /// private readonly StoreActionMatchingMode _actionMatchingMode; /// /// Dispatch 串行化门闩。 /// 该锁保证任意时刻只有一个 action 管线或历史跳转在提交状态,从而保持状态演进顺序确定, /// 同时避免让耗时 middleware / reducer 长时间占用状态锁。 /// private readonly object _dispatchGate = new(); /// /// 历史快照缓冲区。 /// 当容量为 0 时该集合始终为空;启用后会保留当前时间线上的最近若干个状态快照。 /// private readonly List> _history = []; /// /// 历史缓冲区容量。 /// 该容量包含当前状态锚点,因此容量越小,可撤销的步数也越少。 /// private readonly int _historyCapacity; /// /// 当前状态变化订阅者列表。 /// 使用显式订阅对象而不是委托链,便于处理原子初始化订阅、挂起补发和精确解绑。 /// private readonly List _listeners = []; /// /// Store 内部所有可变状态的同步锁。 /// 该锁仅保护状态快照、订阅集合、缓存选择视图、历史记录和注册表本身的短临界区访问。 /// private readonly object _lock = new(); /// /// 已注册的中间件链,按添加顺序执行。 /// 每个条目都持有稳定身份,便于通过注销句柄精确移除而不影响其他同类中间件。 /// Dispatch 开始时会抓取快照,因此运行中的分发不会受到后续注册变化影响。 /// private readonly List _middlewares = []; /// /// 按 action 注册类型组织的 reducer 注册表。 /// 默认使用精确类型匹配;启用多态匹配时,会在分发时按确定性的优先级扫描可赋值类型。 /// private readonly Dictionary> _reducers = []; /// /// 已缓存的局部状态选择视图。 /// 该缓存用于避免高频访问的 Model 属性在每次 getter 调用时都创建新的选择对象。 /// private readonly Dictionary _selectionCache = []; /// /// 用于判断状态是否发生有效变化的比较器。 /// private readonly IEqualityComparer _stateComparer; /// /// 当前批处理嵌套深度。 /// 大于 0 时会推迟状态通知,直到最外层批处理结束。 /// private int _batchDepth; /// /// 当前批处理中是否有待发送的最终状态通知。 /// private bool _hasPendingBatchNotification; /// /// 当前历史游标位置。 /// 当未启用历史记录时,该值保持为 -1。 /// private int _historyIndex = -1; /// /// 标记当前 Store 是否正在执行分发。 /// 该标记用于阻止同一 Store 的重入分发或在 dispatch 中执行历史跳转,避免产生难以推导的执行顺序。 /// private bool _isDispatching; /// /// 最近一次分发的 action 类型。 /// private Type? _lastActionType; /// /// 最近一次分发记录。 /// private StoreDispatchRecord? _lastDispatchRecord; /// /// 最近一次真正改变状态的时间戳。 /// private DateTimeOffset? _lastStateChangedAt; /// /// reducer 注册序号。 /// 该序号用于在多态匹配时为不同注册桶提供跨类型的稳定排序键。 /// private long _nextReducerSequence; /// /// 当前批处理中最后一个应通知给订阅者的状态快照。 /// private TState _pendingBatchState = default!; /// /// 当前 Store 持有的状态快照。 /// private TState _state; /// /// 初始化一个新的 Store。 /// /// Store 的初始状态。 /// 状态比较器;未提供时使用 。 /// 历史缓冲区容量;0 表示不启用历史记录。 /// reducer 的 action 匹配策略。 /// 小于 0 时抛出。 public Store( TState initialState, IEqualityComparer? comparer = null, int historyCapacity = 0, StoreActionMatchingMode actionMatchingMode = StoreActionMatchingMode.ExactTypeOnly) { if (historyCapacity < 0) { throw new ArgumentOutOfRangeException(nameof(historyCapacity), historyCapacity, "History capacity cannot be negative."); } _state = initialState; _stateComparer = comparer ?? EqualityComparer.Default; _historyCapacity = historyCapacity; _actionMatchingMode = actionMatchingMode; if (_historyCapacity > 0) { ResetHistoryToCurrentState(DateTimeOffset.UtcNow); } } /// /// 获取当前状态快照。 /// public TState State { get { lock (_lock) { return _state; } } } /// /// 获取当前是否可以撤销到更早的历史状态。 /// public bool CanUndo { get { lock (_lock) { return _historyCapacity > 0 && _historyIndex > 0; } } } /// /// 获取当前是否可以重做到更晚的历史状态。 /// public bool CanRedo { get { lock (_lock) { return _historyCapacity > 0 && _historyIndex >= 0 && _historyIndex < _history.Count - 1; } } } /// /// 分发一个 action 并按顺序执行匹配的 reducer。 /// /// action 的具体类型。 /// 要分发的 action。 /// 时抛出。 /// 当同一 Store 发生重入分发时抛出。 public void Dispatch(TAction action) { ArgumentNullException.ThrowIfNull(action); Action[] listenersSnapshot = Array.Empty>(); IStoreMiddleware[] middlewaresSnapshot = Array.Empty>(); IStoreReducerAdapter[] reducersSnapshot = Array.Empty(); IEqualityComparer stateComparerSnapshot = _stateComparer; StoreDispatchContext? context = null; TState notificationState = default!; var hasNotification = false; var enteredDispatchScope = false; lock (_dispatchGate) { try { lock (_lock) { EnsureNotDispatching(); _isDispatching = true; enteredDispatchScope = true; context = new StoreDispatchContext(action!, _state); stateComparerSnapshot = _stateComparer; middlewaresSnapshot = CreateMiddlewareSnapshotCore(); reducersSnapshot = CreateReducerSnapshotCore(context.ActionType); } // middleware 和 reducer 可能包含较重的同步逻辑,因此仅持有 dispatch 串行门, // 不占用状态锁,让读取、订阅和注册操作只在需要访问共享状态时短暂阻塞。 ExecuteDispatchPipeline(context, middlewaresSnapshot, reducersSnapshot, stateComparerSnapshot); lock (_lock) { _lastActionType = context.ActionType; _lastDispatchRecord = new StoreDispatchRecord( context.Action, context.PreviousState, context.NextState, context.HasStateChanged, context.DispatchedAt); if (!context.HasStateChanged) { return; } ApplyCommittedStateChange(context.NextState, context.DispatchedAt, context.Action); listenersSnapshot = CaptureListenersOrDeferNotification(context.NextState, out notificationState); hasNotification = listenersSnapshot.Length > 0; } } finally { if (enteredDispatchScope) { lock (_lock) { _isDispatching = false; } } } } if (!hasNotification) { return; } NotifyListeners(listenersSnapshot, notificationState); } /// /// 将当前状态回退到上一个历史点。 /// /// 当历史缓冲区未启用,或当前已经没有可撤销的历史点时抛出。 public void Undo() { MoveToHistoryIndex(-1, isRelative: true, nameof(Undo), "No earlier history entry is available for undo."); } /// /// 将当前状态前进到下一个历史点。 /// /// 当历史缓冲区未启用,或当前已经没有可重做的历史点时抛出。 public void Redo() { MoveToHistoryIndex(1, isRelative: true, nameof(Redo), "No later history entry is available for redo."); } /// /// 跳转到指定索引的历史点。 /// /// 目标历史索引,从 0 开始。 /// 当历史缓冲区未启用时抛出。 /// 超出历史范围时抛出。 public void TimeTravelTo(int historyIndex) { MoveToHistoryIndex(historyIndex, isRelative: false, nameof(historyIndex), null); } /// /// 清空当前撤销/重做历史,并以当前状态作为新的历史锚点。 /// public void ClearHistory() { lock (_dispatchGate) { lock (_lock) { EnsureNotDispatching(); if (_historyCapacity == 0) { return; } ResetHistoryToCurrentState(DateTimeOffset.UtcNow); } } } /// /// 将多个状态操作合并到一个批处理中执行。 /// 批处理内的状态变化会立即提交,但通知会在最外层批处理结束后折叠为一次最终回放。 /// /// 批处理主体。 /// 时抛出。 public void RunInBatch(Action batchAction) { ArgumentNullException.ThrowIfNull(batchAction); lock (_lock) { _batchDepth++; } Action[] listenersSnapshot = Array.Empty>(); TState notificationState = default!; try { batchAction(); } finally { lock (_lock) { if (_batchDepth == 0) { Debug.Fail("Batch depth is already zero during RunInBatch cleanup."); } else { _batchDepth--; if (_batchDepth == 0 && _hasPendingBatchNotification) { notificationState = _pendingBatchState; _pendingBatchState = default!; _hasPendingBatchNotification = false; listenersSnapshot = SnapshotListenersForNotification(notificationState); } } } } if (listenersSnapshot.Length > 0) { NotifyListeners(listenersSnapshot, notificationState); } } /// /// 订阅状态变化通知。 /// /// 状态变化时的监听器。 /// 用于取消订阅的句柄。 /// 时抛出。 public IUnRegister Subscribe(Action listener) { ArgumentNullException.ThrowIfNull(listener); var subscription = new ListenerSubscription(listener); lock (_lock) { _listeners.Add(subscription); } return new DefaultUnRegister(() => UnSubscribe(subscription)); } /// /// 订阅状态变化通知,并立即回放当前状态。 /// /// 状态变化时的监听器。 /// 用于取消订阅的句柄。 /// 时抛出。 public IUnRegister SubscribeWithInitValue(Action listener) { ArgumentNullException.ThrowIfNull(listener); var subscription = new ListenerSubscription(listener) { IsActive = false }; TState currentState; TState? pendingState = default; var hasPendingState = false; lock (_lock) { currentState = _state; _listeners.Add(subscription); } try { listener(currentState); } catch { UnSubscribe(subscription); throw; } lock (_lock) { if (!subscription.IsSubscribed) { return new DefaultUnRegister(() => { }); } subscription.IsActive = true; if (subscription.HasPendingState) { pendingState = subscription.PendingState; hasPendingState = true; subscription.HasPendingState = false; subscription.PendingState = default!; } } if (hasPendingState) { listener(pendingState!); } return new DefaultUnRegister(() => UnSubscribe(subscription)); } /// /// 取消订阅指定监听器。 /// /// 需要移除的监听器。 /// 时抛出。 public void UnSubscribe(Action listener) { ArgumentNullException.ThrowIfNull(listener); lock (_lock) { var index = _listeners.FindIndex(subscription => subscription.Listener == listener); if (index < 0) { return; } _listeners[index].IsSubscribed = false; _listeners.RemoveAt(index); } } /// /// 获取最近一次分发的 action 类型。 /// public Type? LastActionType { get { lock (_lock) { return _lastActionType; } } } /// /// 获取最近一次真正改变状态的时间戳。 /// public DateTimeOffset? LastStateChangedAt { get { lock (_lock) { return _lastStateChangedAt; } } } /// /// 获取当前订阅者数量。 /// public int SubscriberCount { get { lock (_lock) { return _listeners.Count; } } } /// /// 获取最近一次分发记录。 /// public StoreDispatchRecord? LastDispatchRecord { get { lock (_lock) { return _lastDispatchRecord; } } } /// /// 获取当前 Store 使用的 action 匹配策略。 /// public StoreActionMatchingMode ActionMatchingMode => _actionMatchingMode; /// /// 获取历史缓冲区容量。 /// public int HistoryCapacity => _historyCapacity; /// /// 获取当前可见历史记录数量。 /// public int HistoryCount { get { lock (_lock) { return _history.Count; } } } /// /// 获取当前状态在历史缓冲区中的索引。 /// public int HistoryIndex { get { lock (_lock) { return _historyIndex; } } } /// /// 获取当前是否处于批处理阶段。 /// public bool IsBatching { get { lock (_lock) { return _batchDepth > 0; } } } /// /// 获取当前历史快照列表的只读快照。 /// 该方法以方法语义显式表达会分配并返回集合副本,避免把快照克隆隐藏在属性访问中。 /// /// 当前历史快照列表;若未启用历史记录或当前没有历史,则返回空数组。 public IReadOnlyList> GetHistoryEntriesSnapshot() { lock (_lock) { return _history.Count == 0 ? Array.Empty>() : _history.ToArray(); } } /// /// 创建一个用于当前状态类型的 Store 构建器。 /// /// 新的 Store 构建器实例。 public static StoreBuilder CreateBuilder() { return new StoreBuilder(); } /// /// 注册一个强类型 reducer。 /// 同一 action 类型可注册多个 reducer,它们会按照注册顺序依次归约状态。 /// 该重载保留现有链式配置体验;若需要在运行时注销,请改用 。 /// /// reducer 处理的 action 类型。 /// 要注册的 reducer 实例。 /// 当前 Store 实例,便于链式配置。 /// 时抛出。 public Store RegisterReducer(IReducer reducer) { RegisterReducerHandle(reducer); return this; } /// /// 使用委托快速注册一个 reducer。 /// 该重载保留现有链式配置体验;若需要在运行时注销,请改用 。 /// /// reducer 处理的 action 类型。 /// 执行归约的委托。 /// 当前 Store 实例,便于链式配置。 /// 时抛出。 public Store RegisterReducer(Func reducer) { ArgumentNullException.ThrowIfNull(reducer); return RegisterReducer(new DelegateReducer(reducer)); } /// /// 注册一个强类型 reducer,并返回可用于注销该 reducer 的句柄。 /// 该句柄只会移除当前这次注册,不会影响同一 action 类型下的其他 reducer。 /// 若在 dispatch 进行中调用注销,当前这次 dispatch 仍会使用开始时抓取的 reducer 快照, /// 注销仅影响之后的新 dispatch。 /// /// reducer 处理的 action 类型。 /// 要注册的 reducer 实例。 /// 用于注销当前 reducer 注册的句柄。 /// 时抛出。 public IUnRegister RegisterReducerHandle(IReducer reducer) { ArgumentNullException.ThrowIfNull(reducer); var actionType = typeof(TAction); ReducerRegistration registration; lock (_lock) { registration = new ReducerRegistration(new ReducerAdapter(reducer), _nextReducerSequence++); if (!_reducers.TryGetValue(actionType, out var reducers)) { reducers = []; _reducers[actionType] = reducers; } reducers.Add(registration); } return new DefaultUnRegister(() => UnRegisterReducer(actionType, registration)); } /// /// 使用委托快速注册一个 reducer,并返回可用于注销该 reducer 的句柄。 /// 适合测试代码或按场景临时挂载的状态逻辑。 /// /// reducer 处理的 action 类型。 /// 执行归约的委托。 /// 用于注销当前 reducer 注册的句柄。 /// 时抛出。 public IUnRegister RegisterReducerHandle(Func reducer) { ArgumentNullException.ThrowIfNull(reducer); return RegisterReducerHandle(new DelegateReducer(reducer)); } /// /// 添加一个 Store 中间件。 /// 中间件按添加顺序包裹 reducer 执行,可用于日志、审计或调试。 /// 该重载保留现有链式配置体验;若需要在运行时注销,请改用 . /// /// 要添加的中间件实例。 /// 当前 Store 实例,便于链式配置。 /// 时抛出。 public Store UseMiddleware(IStoreMiddleware middleware) { RegisterMiddleware(middleware); return this; } /// /// 注册一个 Store 中间件,并返回可用于注销该中间件的句柄。 /// 中间件按注册顺序包裹 reducer 执行;注销只会移除当前这次注册。 /// 若在 dispatch 进行中调用注销,当前这次 dispatch 仍会使用开始时抓取的中间件快照, /// 注销仅影响之后的新 dispatch。 /// /// 要注册的中间件实例。 /// 用于注销当前中间件注册的句柄。 /// 时抛出。 public IUnRegister RegisterMiddleware(IStoreMiddleware middleware) { ArgumentNullException.ThrowIfNull(middleware); var registration = new MiddlewareRegistration(middleware); lock (_lock) { _middlewares.Add(registration); } return new DefaultUnRegister(() => UnRegisterMiddleware(registration)); } /// /// 获取或创建一个带缓存的局部状态选择视图。 /// 对于会被频繁读取的 Model 只读属性,推荐使用该方法复用同一个选择实例。 /// /// 局部状态类型。 /// 缓存键,调用方应保证同一个键始终表示同一局部状态语义。 /// 状态选择委托。 /// 用于比较局部状态是否变化的比较器。 /// 稳定复用的选择视图实例。 public StoreSelection GetOrCreateSelection( string key, Func selector, IEqualityComparer? comparer = null) { ArgumentNullException.ThrowIfNull(key); ArgumentNullException.ThrowIfNull(selector); lock (_lock) { if (_selectionCache.TryGetValue(key, out var existing)) { if (existing is StoreSelection cachedSelection) { return cachedSelection; } throw new InvalidOperationException( $"A cached selection with key '{key}' already exists with a different selected type."); } var selection = new StoreSelection(this, selector, comparer); _selectionCache[key] = selection; return selection; } } /// /// 获取或创建一个带缓存的只读 BindableProperty 风格视图。 /// /// 局部状态类型。 /// 缓存键,调用方应保证同一个键始终表示同一局部状态语义。 /// 状态选择委托。 /// 用于比较局部状态是否变化的比较器。 /// 稳定复用的只读绑定视图。 public StoreSelection GetOrCreateBindableProperty( string key, Func selector, IEqualityComparer? comparer = null) { return GetOrCreateSelection(key, selector, comparer); } /// /// 执行一次完整分发管线。 /// /// 当前分发上下文。 /// 本次分发使用的中间件快照。 /// 本次分发使用的 reducer 快照。 /// 本次分发使用的状态比较器快照。 private static void ExecuteDispatchPipeline( StoreDispatchContext context, IReadOnlyList> middlewares, IReadOnlyList reducers, IEqualityComparer stateComparer) { Action pipeline = () => ApplyReducers(context, reducers, stateComparer); for (var i = middlewares.Count - 1; i >= 0; i--) { var middleware = middlewares[i]; var next = pipeline; pipeline = () => middleware.Invoke(context, next); } pipeline(); } /// /// 对当前 action 应用所有匹配的 reducer。 /// reducer 会按照预先计算好的稳定顺序执行,从而在多态匹配模式下仍保持确定性的状态演进。 /// /// 当前分发上下文。 /// 本次分发使用的 reducer 快照。 /// 本次分发使用的状态比较器快照。 private static void ApplyReducers( StoreDispatchContext context, IReadOnlyList reducers, IEqualityComparer stateComparer) { if (reducers.Count == 0) { context.NextState = context.PreviousState; context.HasStateChanged = false; return; } var nextState = context.PreviousState; // 多个 reducer 共享同一 action 类型时,后一个 reducer 以前一个 reducer 的输出作为输入, // 从而支持按模块拆分归约逻辑,同时保持总体状态演进顺序明确。 foreach (var reducer in reducers) { nextState = reducer.Reduce(nextState, context.Action); } context.NextState = nextState; context.HasStateChanged = !stateComparer.Equals(context.PreviousState, nextState); } /// /// 确保当前 Store 没有发生重入分发或在 dispatch 中执行历史控制。 /// /// 当检测到重入分发时抛出。 private void EnsureNotDispatching() { if (_isDispatching) { throw new InvalidOperationException("Nested dispatch on the same store is not allowed."); } } /// /// 将新的已提交状态应用到 Store。 /// 该方法负责统一更新当前状态、最后变更时间和历史缓冲区,避免 dispatch 与 time-travel 路径产生分叉语义。 /// /// 要提交的新状态。 /// 状态生效时间。 /// 触发该状态的 action;若本次变化不是由 dispatch 触发,则为 。 private void ApplyCommittedStateChange(TState nextState, DateTimeOffset changedAt, object? action) { _state = nextState; _lastStateChangedAt = changedAt; RecordHistoryEntry(nextState, changedAt, action); } /// /// 从当前订阅集合中提取需要立即通知的监听器快照,并为尚未激活的初始化订阅保存待补发状态。 /// /// 本次分发后的最新状态。 /// 需要在锁外立即调用的监听器快照。 private Action[] SnapshotListenersForNotification(TState nextState) { if (_listeners.Count == 0) { return Array.Empty>(); } var activeListeners = new List>(_listeners.Count); foreach (var subscription in _listeners) { if (!subscription.IsSubscribed) { continue; } if (subscription.IsActive) { activeListeners.Add(subscription.Listener); continue; } subscription.PendingState = nextState; subscription.HasPendingState = true; } return activeListeners.Count > 0 ? activeListeners.ToArray() : Array.Empty>(); } /// /// 根据当前批处理状态决定是立即提取监听器快照,还是把通知折叠到批处理尾部。 /// /// 最新状态快照。 /// 若需要立即通知,则返回要回放给监听器的状态。 /// 需要立即通知的监听器快照;若处于批处理阶段则返回空数组。 private Action[] CaptureListenersOrDeferNotification(TState nextState, out TState notificationState) { if (_batchDepth > 0) { _pendingBatchState = nextState; _hasPendingBatchNotification = true; notificationState = default!; return Array.Empty>(); } notificationState = nextState; return SnapshotListenersForNotification(nextState); } /// /// 为当前中间件链创建快照。 /// 调用该方法时必须已经持有状态锁,从而避免额外的锁重入和快照时序歧义。 /// /// 当前中间件链的快照;若未注册则返回空数组。 private IStoreMiddleware[] CreateMiddlewareSnapshotCore() { Debug.Assert( Monitor.IsEntered(_lock), "Caller must hold _lock before invoking CreateMiddlewareSnapshotCore to avoid concurrency bugs."); if (_middlewares.Count == 0) { return Array.Empty>(); } var snapshot = new IStoreMiddleware[_middlewares.Count]; for (var i = 0; i < _middlewares.Count; i++) { snapshot[i] = _middlewares[i].Middleware; } return snapshot; } /// /// 为当前 action 类型创建 reducer 快照。 /// 在精确匹配模式下只读取一个注册桶;在多态模式下会按稳定排序规则合并可赋值的基类和接口注册。 /// /// 当前分发的 action 类型。 /// 对应 action 类型的 reducer 快照;若未注册则返回空数组。 private IStoreReducerAdapter[] CreateReducerSnapshotCore(Type actionType) { Debug.Assert( Monitor.IsEntered(_lock), "Caller must hold _lock before invoking CreateReducerSnapshotCore to avoid concurrency bugs."); if (_actionMatchingMode == StoreActionMatchingMode.ExactTypeOnly) { if (!_reducers.TryGetValue(actionType, out var exactReducers) || exactReducers.Count == 0) { return Array.Empty(); } var exactSnapshot = new IStoreReducerAdapter[exactReducers.Count]; for (var i = 0; i < exactReducers.Count; i++) { exactSnapshot[i] = exactReducers[i].Adapter; } return exactSnapshot; } List? matches = null; foreach (var reducerBucket in _reducers) { if (!TryCreateReducerMatch(actionType, reducerBucket.Key, out var matchCategory, out var inheritanceDistance)) { continue; } matches ??= new List(); foreach (var registration in reducerBucket.Value) { matches.Add(new ReducerMatch( registration.Adapter, registration.Sequence, matchCategory, inheritanceDistance)); } } if (matches is null || matches.Count == 0) { return Array.Empty(); } matches.Sort(static (left, right) => { var categoryComparison = left.MatchCategory.CompareTo(right.MatchCategory); if (categoryComparison != 0) { return categoryComparison; } var distanceComparison = left.InheritanceDistance.CompareTo(right.InheritanceDistance); if (distanceComparison != 0) { return distanceComparison; } return left.Sequence.CompareTo(right.Sequence); }); var snapshot = new IStoreReducerAdapter[matches.Count]; for (var i = 0; i < matches.Count; i++) { snapshot[i] = matches[i].Adapter; } return snapshot; } /// /// 判断指定 reducer 注册类型是否能匹配当前 action 类型,并给出用于稳定排序的分类信息。 /// /// 当前 action 的运行时类型。 /// reducer 注册时声明的 action 类型。 /// 匹配分类:0 为精确类型,1 为基类,2 为接口。 /// 继承距离,值越小表示越接近当前 action 类型。 /// 若可以匹配则返回 private static bool TryCreateReducerMatch( Type actionType, Type registeredActionType, out int matchCategory, out int inheritanceDistance) { if (registeredActionType == actionType) { matchCategory = 0; inheritanceDistance = 0; return true; } if (!registeredActionType.IsAssignableFrom(actionType)) { matchCategory = default; inheritanceDistance = default; return false; } if (registeredActionType.IsInterface) { matchCategory = 2; inheritanceDistance = 0; return true; } matchCategory = 1; inheritanceDistance = GetInheritanceDistance(actionType, registeredActionType); return true; } /// /// 计算当前 action 类型到目标基类的继承距离。 /// 距离越小表示基类越接近当前 action 类型,在多态匹配排序中优先级越高。 /// /// 当前 action 的运行时类型。 /// reducer 注册时声明的基类类型。 /// 从当前 action 到目标基类的继承层级数。 private static int GetInheritanceDistance(Type actionType, Type registeredActionType) { var distance = 0; var currentType = actionType; while (currentType != registeredActionType && currentType.BaseType is not null) { currentType = currentType.BaseType; distance++; } return distance; } /// /// 记录一条新的历史快照。 /// 当当前游标不在时间线末尾时,会先裁掉 redo 分支,再追加新的状态快照。 /// /// 要记录的状态快照。 /// 历史记录时间。 /// 触发该状态的 action;若为空则表示当前变化不应写入历史。 private void RecordHistoryEntry(TState state, DateTimeOffset recordedAt, object? action) { if (_historyCapacity == 0) { return; } if (action is null) { return; } if (_historyIndex >= 0 && _historyIndex < _history.Count - 1) { _history.RemoveRange(_historyIndex + 1, _history.Count - _historyIndex - 1); } _history.Add(new StoreHistoryEntry(state, recordedAt, action)); _historyIndex = _history.Count - 1; if (_history.Count <= _historyCapacity) { return; } var overflow = _history.Count - _historyCapacity; _history.RemoveRange(0, overflow); _historyIndex = Math.Max(0, _historyIndex - overflow); } /// /// 将当前状态重置为新的历史锚点。 /// 该操作用于 Store 初始化和显式清空历史后重新建立时间线起点。 /// /// 锚点记录时间。 private void ResetHistoryToCurrentState(DateTimeOffset recordedAt) { _history.Clear(); _history.Add(new StoreHistoryEntry(_state, recordedAt)); _historyIndex = 0; } /// /// 将当前状态移动到指定历史索引。 /// 该方法统一承载 Undo、Redo 和显式时间旅行路径,确保通知与批处理语义保持一致。 /// /// 目标索引或相对偏移量。 /// 是否按相对偏移量解释 。 /// 参数名,用于异常信息。 /// 当相对跳转无可用历史时的错误信息;绝对跳转场景传 。 private void MoveToHistoryIndex( int historyIndexOrOffset, bool isRelative, string argumentName, string? emptyHistoryMessage) { Action[] listenersSnapshot = Array.Empty>(); TState notificationState = default!; lock (_dispatchGate) { lock (_lock) { EnsureNotDispatching(); EnsureHistoryEnabled(); var targetIndex = isRelative ? _historyIndex + historyIndexOrOffset : historyIndexOrOffset; if (targetIndex < 0 || targetIndex >= _history.Count) { if (isRelative) { throw new InvalidOperationException(emptyHistoryMessage); } throw new ArgumentOutOfRangeException(argumentName, historyIndexOrOffset, "History index is out of range."); } if (targetIndex == _historyIndex) { return; } _historyIndex = targetIndex; notificationState = _history[targetIndex].State; _state = notificationState; _lastStateChangedAt = DateTimeOffset.UtcNow; listenersSnapshot = CaptureListenersOrDeferNotification(notificationState, out notificationState); } } if (listenersSnapshot.Length > 0) { NotifyListeners(listenersSnapshot, notificationState); } } /// /// 确保当前 Store 已启用历史缓冲区。 /// /// 当历史记录未启用时抛出。 private void EnsureHistoryEnabled() { if (_historyCapacity == 0) { throw new InvalidOperationException("History is not enabled for this store."); } } /// /// 在锁外顺序通知监听器。 /// 始终在锁外通知可避免监听器内部读取 Store 或执行额外逻辑时产生死锁。 /// /// 监听器快照。 /// 要回放给监听器的状态。 private static void NotifyListeners(Action[] listenersSnapshot, TState state) { foreach (var listener in listenersSnapshot) { listener(state); } } /// /// 解绑一个精确的订阅对象。 /// /// 要解绑的订阅对象。 private void UnSubscribe(ListenerSubscription subscription) { lock (_lock) { subscription.IsSubscribed = false; _listeners.Remove(subscription); } } /// /// 注销一个中间件注册条目。 /// 仅精确移除与当前句柄关联的条目,避免误删同一实例的其他重复注册。 /// /// 要移除的中间件注册条目。 private void UnRegisterMiddleware(MiddlewareRegistration registration) { lock (_lock) { _middlewares.Remove(registration); } } /// /// 注销一个 reducer 注册条目。 /// 若该 action 类型下已无其他 reducer,则同时清理空注册桶,保持注册表紧凑。 /// /// reducer 对应的 action 类型。 /// 要移除的 reducer 注册条目。 private void UnRegisterReducer(Type actionType, ReducerRegistration registration) { lock (_lock) { if (!_reducers.TryGetValue(actionType, out var reducers)) { return; } reducers.Remove(registration); if (reducers.Count == 0) { _reducers.Remove(actionType); } } } /// /// 适配不同 action 类型 reducer 的内部统一接口。 /// Store 通过该接口在运行时按 action 具体类型执行 reducer,而不暴露内部装配细节。 /// private interface IStoreReducerAdapter { /// /// 使用当前 action 对状态进行一次归约。 /// /// 当前状态。 /// 分发中的 action。 /// 归约后的下一状态。 TState Reduce(TState currentState, object action); } /// /// 基于强类型 reducer 的适配器实现。 /// 该适配器仅负责安全地完成 object 到 action 类型的转换,然后委托给真实 reducer。 /// /// 当前适配器负责处理的 action 类型。 private sealed class ReducerAdapter(IReducer reducer) : IStoreReducerAdapter { /// /// 包装后的强类型 reducer 实例。 /// private readonly IReducer _reducer = reducer ?? throw new ArgumentNullException(nameof(reducer)); /// /// 将运行时 action 转换为强类型 action 后执行归约。 /// /// 当前状态。 /// 运行时 action。 /// 归约后的下一状态。 public TState Reduce(TState currentState, object action) { return _reducer.Reduce(currentState, (TAction)action); } } /// /// 表示一条 reducer 注册记录。 /// 该包装对象为运行时注销提供稳定身份,并携带全局序号以支撑多态匹配时的稳定排序。 /// private sealed class ReducerRegistration(IStoreReducerAdapter adapter, long sequence) { /// /// 获取真正执行归约的内部适配器。 /// public IStoreReducerAdapter Adapter { get; } = adapter; /// /// 获取该 reducer 的全局注册序号。 /// public long Sequence { get; } = sequence; } /// /// 表示一次多态 reducer 匹配结果。 /// 该结构在创建快照时缓存排序所需元数据,避免排序阶段重复计算类型关系。 /// private sealed class ReducerMatch( IStoreReducerAdapter adapter, long sequence, int matchCategory, int inheritanceDistance) { /// /// 获取匹配到的 reducer 适配器。 /// public IStoreReducerAdapter Adapter { get; } = adapter; /// /// 获取 reducer 的全局注册序号。 /// public long Sequence { get; } = sequence; /// /// 获取匹配分类:0 为精确类型,1 为基类,2 为接口。 /// public int MatchCategory { get; } = matchCategory; /// /// 获取继承距离。 /// 该值越小表示注册类型越接近当前 action 类型。 /// public int InheritanceDistance { get; } = inheritanceDistance; } /// /// 基于委托的 reducer 适配器实现,便于快速在测试和应用代码中声明 reducer。 /// /// 当前适配器负责处理的 action 类型。 private sealed class DelegateReducer(Func reducer) : IReducer { /// /// 真正执行归约的委托。 /// private readonly Func _reducer = reducer ?? throw new ArgumentNullException(nameof(reducer)); /// /// 执行一次委托归约。 /// /// 当前状态。 /// 当前 action。 /// 归约后的下一状态。 public TState Reduce(TState currentState, TAction action) { return _reducer(currentState, action); } } /// /// 表示一条中间件注册记录。 /// 通过显式注册对象而不是直接存储中间件实例,可在重复注册同一实例时保持精确注销。 /// private sealed class MiddlewareRegistration(IStoreMiddleware middleware) { /// /// 获取注册的中间件实例。 /// public IStoreMiddleware Middleware { get; } = middleware; } /// /// 表示一个 Store 状态监听订阅。 /// 该对象用于支持初始化回放与正式订阅之间的原子衔接,避免 SubscribeWithInitValue 漏掉状态变化。 /// private sealed class ListenerSubscription(Action listener) { /// /// 获取订阅回调。 /// public Action Listener { get; } = listener; /// /// 获取或设置订阅是否已激活。 /// 非激活状态表示正在执行初始化回放,此时新的状态变化会被暂存为待补发值。 /// public bool IsActive { get; set; } = true; /// /// 获取或设置订阅是否仍然有效。 /// public bool IsSubscribed { get; set; } = true; /// /// 获取或设置是否存在待补发的最新状态。 /// public bool HasPendingState { get; set; } /// /// 获取或设置初始化阶段积累的最新状态。 /// public TState PendingState { get; set; } = default!; } }