GFramework/docs/zh-CN/core/command.md
gewuyou 6056159866 fix(core): 收口 legacy cqrs bridge 评审问题
- 修复 legacy bridge 测试装配与清理流程,改用 InternalsVisibleTo 和显式 handler 注册,补齐共享计数器重置与生命周期说明

- 优化 CommandExecutor、QueryExecutor 与相关模块的 runtime 契约,补充 XML 文档、nullable 注解和显式依赖解析

- 更新 legacy 异步 bridge 的取消语义、兼容文档回退边界以及 cqrs-rewrite active tracking/trace
2026-05-07 17:54:05 +08:00

3.7 KiB
Raw Blame History

title, description
title description
命令Command 说明 GFramework.Core.Command 旧命令体系的兼容定位、可用基类与当前使用约束。

命令Command

本页只说明 GFramework.Core.Command 里的旧命令体系。

它仍然被保留,用来兼容存量代码;但如果你在写新功能,优先使用 cqrs 里的新请求模型。

当前仍然可用的基类

旧命令体系当前最常见的三个基类是:

  • AbstractCommand
    • 无输入、无返回值
  • AbstractCommand<TInput>
    • 有输入、无返回值
  • AbstractCommand<TInput, TResult>
    • 有输入、有返回值

当前泛型命令通过构造函数接收输入,而不是依赖 Input 可写属性。

无输入命令

using GFramework.Core.Command;
using GFramework.Core.Extensions;

public sealed class RestoreHealthCommand : AbstractCommand
{
    protected override void OnExecute()
    {
        var playerModel = this.GetModel<PlayerModel>();
        playerModel.Health.Value = playerModel.MaxHealth.Value;
        this.SendEvent(new PlayerHealthRestoredEvent());
    }
}

发送方式:

this.SendCommand(new RestoreHealthCommand());

带输入命令

旧命令输入类型现在直接复用 CQRS 抽象层里的 ICommandInput

using GFramework.Core.Command;
using GFramework.Core.Extensions;
using GFramework.Cqrs.Abstractions.Cqrs.Command;

public sealed record DamagePlayerInput(int Amount) : ICommandInput;

public sealed class DamagePlayerCommand(DamagePlayerInput input)
    : AbstractCommand<DamagePlayerInput>(input)
{
    protected override void OnExecute(DamagePlayerInput input)
    {
        var playerModel = this.GetModel<PlayerModel>();
        playerModel.Health.Value -= input.Amount;
    }
}

发送方式:

this.SendCommand(new DamagePlayerCommand(new DamagePlayerInput(10)));

带返回值命令

using GFramework.Core.Command;
using GFramework.Core.Extensions;
using GFramework.Cqrs.Abstractions.Cqrs.Command;

public sealed record GetGoldRewardInput(int EnemyLevel) : ICommandInput;

public sealed class GetGoldRewardCommand(GetGoldRewardInput input)
    : AbstractCommand<GetGoldRewardInput, int>(input)
{
    protected override int OnExecute(GetGoldRewardInput input)
    {
        return input.EnemyLevel * 10;
    }
}
var reward = this.SendCommand(new GetGoldRewardCommand(new GetGoldRewardInput(3)));

发送入口

旧命令由 IArchitectureContext 的兼容入口执行:

  • SendCommand(ICommand)
  • SendCommand<TResult>(ICommand<TResult>)
  • SendCommandAsync(IAsyncCommand)
  • SendCommandAsync<TResult>(IAsyncCommand<TResult>)

在标准架构启动路径中,这些兼容入口底层已经统一改走 ICqrsRuntime。 这意味着历史命令调用链在不改调用方式的前提下,也会复用同一套 pipeline 与上下文注入语义。 只有在你直接 new CommandExecutor() 做隔离测试,且没有提供 ICqrsRuntime 时,才会回退到 legacy 直接执行;此时不会注入统一 pipeline也不会额外补上下文桥接链路。

IContextAware 对象内,通常直接通过扩展使用:

using GFramework.Core.Extensions;

什么时候还应该用旧命令

  • 你在维护既有 Core.Command 代码
  • 你的调用链已经依赖旧 CommandExecutor
  • 当前改动目标是局部修复,不值得同时做 CQRS 迁移

什么时候该切到 CQRS

下面这些场景更适合新 CQRS runtime

  • 需要 request / notification / stream 的统一模型
  • 需要 pipeline behaviors
  • 需要 handler registry 生成器
  • 你正在写新的业务模块,而不是维护历史命令代码

迁移后常见写法见:cqrs