From bd29475748cc06fe4b9d31aeb8545e19a159fd9b Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Tue, 24 Mar 2026 19:39:55 +0800 Subject: [PATCH] =?UTF-8?q?refactor(store):=20=E6=B7=BB=E5=8A=A0=E8=B0=83?= =?UTF-8?q?=E8=AF=95=E6=96=AD=E8=A8=80=E7=A1=AE=E4=BF=9D=E7=BA=BF=E7=A8=8B?= =?UTF-8?q?=E5=AE=89=E5=85=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 CreateMiddlewareSnapshotCore 方法中添加锁持有检查 - 在 CreateReducerSnapshotCore 方法中添加锁持有检查 - 确保并发安全性避免竞态条件 - 导入 System.Diagnostics 命名空间支持断言功能 --- GFramework.Core/StateManagement/Store.cs | 348 ++++++++++++----------- 1 file changed, 178 insertions(+), 170 deletions(-) diff --git a/GFramework.Core/StateManagement/Store.cs b/GFramework.Core/StateManagement/Store.cs index 9f47e56..28c93b1 100644 --- a/GFramework.Core/StateManagement/Store.cs +++ b/GFramework.Core/StateManagement/Store.cs @@ -157,6 +157,48 @@ public sealed class Store : IStore, IStoreDiagnostics } } + /// + /// 获取最近一次分发的 action 类型。 + /// + public Type? LastActionType + { + get + { + lock (_lock) + { + return _lastActionType; + } + } + } + + /// + /// 获取最近一次真正改变状态的时间戳。 + /// + public DateTimeOffset? LastStateChangedAt + { + get + { + lock (_lock) + { + return _lastStateChangedAt; + } + } + } + + /// + /// 获取当前历史快照列表。 + /// + public IReadOnlyList> HistoryEntries + { + get + { + lock (_lock) + { + return _history.Count == 0 ? Array.Empty>() : _history.ToArray(); + } + } + } + /// /// 获取当前状态快照。 /// @@ -278,54 +320,6 @@ public sealed class Store : IStore, IStoreDiagnostics NotifyListeners(listenersSnapshot, notificationState); } - /// - /// 将多个状态操作合并到一个批处理中执行。 - /// 批处理内的状态变化会立即提交,但通知会在最外层批处理结束后折叠为一次最终回放。 - /// - /// 批处理主体。 - /// 时抛出。 - 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) - { - throw new InvalidOperationException("Batch depth is already zero."); - } - - _batchDepth--; - if (_batchDepth == 0 && _hasPendingBatchNotification) - { - notificationState = _pendingBatchState; - _pendingBatchState = default!; - _hasPendingBatchNotification = false; - listenersSnapshot = SnapshotListenersForNotification(notificationState); - } - } - } - - if (listenersSnapshot.Length > 0) - { - NotifyListeners(listenersSnapshot, notificationState); - } - } - /// /// 将当前状态回退到上一个历史点。 /// @@ -375,6 +369,134 @@ public sealed class Store : IStore, IStoreDiagnostics } } + /// + /// 获取当前订阅者数量。 + /// + 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 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) + { + throw new InvalidOperationException("Batch depth is already zero."); + } + + _batchDepth--; + if (_batchDepth == 0 && _hasPendingBatchNotification) + { + notificationState = _pendingBatchState; + _pendingBatchState = default!; + _hasPendingBatchNotification = false; + listenersSnapshot = SnapshotListenersForNotification(notificationState); + } + } + } + + if (listenersSnapshot.Length > 0) + { + NotifyListeners(listenersSnapshot, notificationState); + } + } + /// /// 订阅状态变化通知。 /// @@ -476,128 +598,6 @@ public sealed class Store : IStore, IStoreDiagnostics } } - /// - /// 获取最近一次分发的 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 IReadOnlyList> HistoryEntries - { - get - { - lock (_lock) - { - return _history.Count == 0 ? Array.Empty>() : _history.ToArray(); - } - } - } - - /// - /// 获取当前是否处于批处理阶段。 - /// - public bool IsBatching - { - get - { - lock (_lock) - { - return _batchDepth > 0; - } - } - } - /// /// 创建一个用于当前状态类型的 Store 构建器。 /// @@ -915,6 +915,10 @@ public sealed class Store : IStore, IStoreDiagnostics /// 当前中间件链的快照;若未注册则返回空数组。 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>(); @@ -937,6 +941,10 @@ public sealed class Store : IStore, IStoreDiagnostics /// 对应 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)