You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
添加单元测试,覆盖批处理行为、历史操作(撤销、重做、时间旅行、分支重置)、多态匹配顺序、StoreBuilder 配置,以及 Store 到 EventBus 的桥接(包括拆卸/回收行为)。
Original summary in English
Summary by Sourcery
Extend the centralized state store with optional history, batching, polymorphic action matching, and EventBus bridging capabilities, and wire them into the builder, diagnostics, documentation, and tests.
New Features:
Add configurable history buffering with undo, redo, time-travel, and ClearHistory support on Store and its abstractions.
Introduce batch execution via RunInBatch that collapses multiple state changes into a single final notification, with nesting support.
Add polymorphic action matching for reducers, configurable via StoreActionMatchingMode and exposed through StoreBuilder.
Provide Store-to-EventBus bridge extensions and corresponding dispatched/state-changed event types for compatibility with existing EventBus consumers.
Enhancements:
Extend reducer registration to track a global sequence and compute deterministic ordering across polymorphic matches.
Expose history, batching, and action-matching-related diagnostics (capacity, count, index, entries, flags) from the Store diagnostics interface.
Update StoreBuilder to construct stores with configurable history capacity and action matching mode.
Documentation:
Update state management documentation to describe history/undo-redo/time-travel, batching semantics, polymorphic action matching, and StoreBuilder configuration options, and clarify recommended usage patterns.
Tests:
Add unit tests covering batching behavior, history operations (undo, redo, time travel, branch reset), polymorphic matching order, StoreBuilder configuration, and Store-to-EventBus bridging including teardown behavior.
Extends the Store state container with optional history (undo/redo/time-travel), batched notifications, polymorphic action matching, EventBus bridge events, and corresponding builder options, plus tests and documentation updates.
Sequence diagram for dispatch with history tracking and batched notifications
sequenceDiagram
actor Client
participant Store_TState_ as Store
participant MiddlewareChain
participant Reducers
participant Subscribers
rect rgb(235,235,255)
Client->>Store_TState_: RunInBatch(batchAction)
activate Store_TState_
Store_TState_->>Store_TState_: increment _batchDepth
Store_TState_->>Store_TState_: execute batchAction()
note over Client,Store_TState_: Inside batchAction, multiple Dispatch calls
end
loop each action in batch
Client->>Store_TState_: Dispatch_TAction_(action)
activate Store_TState_
Store_TState_->>Store_TState_: EnsureNotDispatching()
Store_TState_->>Store_TState_: CreateMiddlewareSnapshotCore()
Store_TState_->>Store_TState_: CreateReducerSnapshotCore(action.GetType())
Store_TState_->>MiddlewareChain: ExecuteDispatchPipeline(context, middlewares, reducers)
activate MiddlewareChain
MiddlewareChain->>Reducers: ApplyReducers(context)
activate Reducers
Reducers-->>MiddlewareChain: newState
deactivate Reducers
MiddlewareChain-->>Store_TState_: context.NextState, context.DispatchedAt
deactivate MiddlewareChain
Store_TState_->>Store_TState_: ApplyCommittedStateChange(nextState, changedAt, action)
Store_TState_->>Store_TState_: CaptureListenersOrDeferNotification(nextState, out notificationState)
alt batching active (_batchDepth > 0)
Store_TState_->>Store_TState_: store pendingBatchState, hasPendingBatchNotification = true
Store_TState_-->>Client: return without notifying
else not batching
Store_TState_->>Subscribers: NotifyListeners(listenersSnapshot, notificationState)
end
deactivate Store_TState_
end
rect rgb(235,255,235)
Store_TState_->>Store_TState_: decrement _batchDepth
alt leaving outermost batch and hasPendingBatchNotification
Store_TState_->>Store_TState_: listenersSnapshot = SnapshotListenersForNotification(pendingBatchState)
Store_TState_->>Store_TState_: clear pendingBatchState, hasPendingBatchNotification
Store_TState_->>Subscribers: NotifyListeners(listenersSnapshot, pendingBatchState)
else inner batch or no state change
Store_TState_-->>Client: no notification
end
deactivate Store_TState_
end
note over Store_TState_: Each ApplyCommittedStateChange also RecordHistoryEntry to history buffer when enabled
Loading
Sequence diagram for Store to EventBus bridge on dispatch and state change
sequenceDiagram
actor Client
participant Store_TState_ as Store
participant EventBus
participant DispatchMiddleware as DispatchEventBusMiddleware_TState_
participant StateBridge as StoreSubscriber
participant DispatchConsumer
participant StateConsumer
rect rgb(235,235,255)
Client->>Store_TState_: BridgeToEventBus_TState_(eventBus)
activate Store_TState_
Store_TState_->>Store_TState_: RegisterMiddleware(DispatchEventBusMiddleware_TState_)
Store_TState_->>Store_TState_: Subscribe(state => Send StoreStateChangedEvent_TState_)
Store_TState_-->>Client: bridge IUnRegister
deactivate Store_TState_
EventBus->>DispatchConsumer: Register<StoreDispatchedEvent_TState_>()
EventBus->>StateConsumer: Register<StoreStateChangedEvent_TState_>()
end
rect rgb(235,255,235)
Client->>Store_TState_: Dispatch_TAction_(action)
activate Store_TState_
Store_TState_->>DispatchMiddleware: Invoke(context, next)
activate DispatchMiddleware
DispatchMiddleware->>Store_TState_: next() (continue dispatch pipeline)
Store_TState_->>Store_TState_: reducers update State
Store_TState_->>StateBridge: NotifyListeners(State)
activate StateBridge
StateBridge->>EventBus: Send(StoreStateChangedEvent_TState_)
deactivate StateBridge
DispatchMiddleware->>EventBus: Send(StoreDispatchedEvent_TState_)
deactivate DispatchMiddleware
deactivate Store_TState_
end
EventBus-->>DispatchConsumer: StoreDispatchedEvent_TState_
EventBus-->>StateConsumer: StoreStateChangedEvent_TState_
note over Store_TState_,EventBus: In batched dispatch, StoreStateChangedEvent_TState_ is only sent once with final state
Loading
Updated class diagram for Store state management with history, batching, polymorphic matching, and EventBus bridge
Add optional history buffer with undo/redo/time-travel APIs and diagnostics surface.
Extend Store with history list, capacity and index tracking, and constructor parameter to enable history
Expose CanUndo/CanRedo and history-related diagnostics (capacity, count, index, entries) on IStore and IStoreDiagnostics
Implement ApplyCommittedStateChange, RecordHistoryEntry, ResetHistoryToCurrentState, MoveToHistoryIndex and EnsureHistoryEnabled to centralize history updates and cursor movement
Add Undo/Redo/TimeTravelTo/ClearHistory public APIs that coordinate with dispatch gate and listener notification logic
Trigger a new review: Comment @sourcery-ai review on the pull request.
Continue discussions: Reply directly to Sourcery's review comments.
Generate a GitHub issue from a review comment: Ask Sourcery to create an
issue from a review comment by replying to it. You can also reply to a
review comment with @sourcery-ai issue to create an issue from it.
Generate a pull request title: Write @sourcery-ai anywhere in the pull
request title to generate a title at any time. You can also comment @sourcery-ai title on the pull request to (re-)generate the title at any time.
Generate a pull request summary: Write @sourcery-ai summary anywhere in
the pull request body to generate a PR summary at any time exactly where you
want it. You can also comment @sourcery-ai summary on the pull request to
(re-)generate the summary at any time.
Generate reviewer's guide: Comment @sourcery-ai guide on the pull
request to (re-)generate the reviewer's guide at any time.
Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
pull request to resolve all Sourcery comments. Useful if you've already
addressed all the comments and don't want to see them anymore.
Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
request to dismiss all existing Sourcery reviews. Especially useful if you
want to start fresh with a new review - don't forget to comment @sourcery-ai review to trigger a new review!
We reviewed changes in b912e6a...e5da5aa on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.
The reason will be displayed to describe this comment to others. Learn more.
Exception being thrown from `finally` block
The finally block is used to clean up resources that may have been allocated in the try block. Throwing any exceptions from the finally block may prevent it from executing fully and also affect the stack trace. It is therefore recommended that you switch to a more suitable alternative.
请帮我变得更有用!欢迎在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的评审。
Original comment in English
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments### Comment 1
<locationpath="GFramework.Core/StateManagement/Store.cs"line_range="916-925" />
<code_context>
+ private IStoreMiddleware<TState>[] CreateMiddlewareSnapshotCore()
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Consider enforcing the "must hold _lock" precondition at runtime to avoid accidental misuse of the snapshot helpers.
These `private` helpers assume the caller already holds `_lock`, but that contract is only documented in XML. Consider adding a defensive runtime check (e.g. `Debug.Assert(Monitor.IsEntered(_lock))`) to enforce the precondition and surface any future call sites that invoke them without the lock, avoiding subtle concurrency bugs after refactors.
Suggested implementation:
```csharp/// <returns>当前中间件链的快照;若未注册则返回空数组。</returns>privateIStoreMiddleware<TState>[] CreateMiddlewareSnapshotCore()
{
System.Diagnostics.Debug.Assert(
System.Threading.Monitor.IsEntered(_lock),
"Caller must hold _lock before invoking CreateMiddlewareSnapshotCore to avoid concurrency bugs."
);
if (_middlewares.Count==0)
{
```
Ifyourcodebaseprefersnamespace-level `using` directivesfor `System.Diagnostics` and `System.Threading`, youcaninsteadadd:- `usingSystem.Diagnostics;`
- `usingSystem.Threading;`
atthetopofthefileandthensimplifytheassertionto `Debug.Assert(Monitor.IsEntered(_lock));`.
</issue_to_address>
Sourcery is free for open source - if you like our reviews please consider sharing them ✨
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary by Sourcery
使用可选的历史记录、批处理、多态动作匹配以及 EventBus 桥接能力扩展集中式状态存储(state store),并将这些能力接入到构建器(builder)、诊断(diagnostics)、文档和测试中。
新功能:
RunInBatch实现的批量执行,将多次状态变更折叠为一次最终通知,并支持嵌套调用。StoreActionMatchingMode进行配置,并通过StoreBuilder对外暴露。增强项:
StoreBuilder,以便在构建 store 时可配置历史容量和动作匹配模式。文档:
StoreBuilder的配置选项,并澄清推荐的使用模式。测试:
StoreBuilder配置,以及 Store 到 EventBus 的桥接(包括拆卸/回收行为)。Original summary in English
Summary by Sourcery
Extend the centralized state store with optional history, batching, polymorphic action matching, and EventBus bridging capabilities, and wire them into the builder, diagnostics, documentation, and tests.
New Features:
Enhancements:
Documentation:
Tests: