You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不修改命令接口的前提下向装饰器传递上下文数据?

如何在不修改命令接口的前提下向装饰器传递上下文数据?

嗨,这个问题我之前做类似的命令扩展功能时也碰到过,完全理解你不想破坏原有接口设计的心情!下面给你几个实用的方案,都不用动你的IActionCommand接口和现有命令类:

方案一:扩展ActionModel存储上下文(最推荐)

你的ActionModel本来就定义为“可以包含任何与动作相关的参数、元数据”,那直接给它加一个可选的上下文属性就好了,完全符合它的设计初衷,也不用改接口方法签名。

首先扩展你的模型类:

// 新增上下文类,用来存触发源等信息
public class CommandExecutionContext
{
    public string TriggerSource { get; set; } // 比如"Hotkey"、"UIButton"
    // 还可以加其他需要的上下文字段,比如触发时间、用户ID等
}

public class ActionModel
{
    // 你原有的属性
    public object ActionParameters { get; set; }
    
    // 新增可选的上下文属性,默认可以为null
    public CommandExecutionContext ExecutionContext { get; set; }
}

然后修改你的分析装饰器,读取这个上下文:

public class AnyActionCommandAnalyticsDecorator : ActionCommandDecorator
{
    private readonly AnalyticsService _analyticsService = new AnalyticsService();

    public AnyActionCommandAnalyticsDecorator(IActionCommand decorator) : base(decorator) { }

    public override void ExeciteAction(ActionModel actionModel)
    {
        // 读取触发源,默认设为"Unknown"避免空引用
        var triggerSource = actionModel.ExecutionContext?.TriggerSource ?? "Unknown";
        _analyticsService.SendData(new AnalyticsModel { TriggerSource = triggerSource });
        
        // 执行原命令逻辑
        Decorator.ExeciteAction(actionModel);
    }
}

调用的时候,只需要在创建ActionModel时传入上下文就行:

// UI按钮触发的场景
var uiActionModel = new ActionModel
{
    ActionParameters = yourParams,
    ExecutionContext = new CommandExecutionContext { TriggerSource = "UIButton" }
};

var command = new AnyActionCommandAnalyticsDecorator(new AnyActionCommand());
command.ExeciteAction(uiActionModel);

// 快捷键触发的场景同理
var hotkeyActionModel = new ActionModel
{
    ActionParameters = yourParams,
    ExecutionContext = new CommandExecutionContext { TriggerSource = "Hotkey" }
};
command.ExeciteAction(hotkeyActionModel);

这个方案最省心,完全贴合现有代码结构,也容易维护和扩展。

方案二:用AsyncLocal存储上下文(适合复杂调用链)

如果你的命令调用链比较长,或者上下文数据不好直接通过ActionModel传递(比如中间层不允许修改ActionModel),可以用.NET的AsyncLocal来存储上下文——它能保证在同一个异步执行流里,上下文数据是隔离的,不会互相干扰。

先创建一个静态的上下文持有者:

public static class CommandContextHolder
{
    // AsyncLocal适合异步场景,同步场景用ThreadLocal也可以
    private static readonly AsyncLocal<CommandExecutionContext> _currentContext = new AsyncLocal<CommandExecutionContext>();

    public static CommandExecutionContext CurrentContext
    {
        get => _currentContext.Value;
        set => _currentContext.Value = value;
    }
}

然后在触发命令之前设置上下文,执行完记得清理:

// 快捷键触发的场景
CommandContextHolder.CurrentContext = new CommandExecutionContext { TriggerSource = "Hotkey" };
try
{
    var command = new AnyActionCommandAnalyticsDecorator(new AnyActionCommand());
    command.ExeciteAction(actionModel);
}
finally
{
    // 必须清理,避免污染后续的命令执行
    CommandContextHolder.CurrentContext = null;
}

最后在装饰器里直接读取上下文:

public override void ExeciteAction(ActionModel actionModel)
{
    var triggerSource = CommandContextHolder.CurrentContext?.TriggerSource ?? "Unknown";
    _analyticsService.SendData(new AnalyticsModel { TriggerSource = triggerSource });
    Decorator.ExeciteAction(actionModel);
}

这个方案的好处是完全不用修改任何模型或接口,缺点是上下文是隐式传递的,新人接手可能需要花点时间理解数据流向。

方案三:给装饰器添加可设置的属性(适合上下文固定的场景)

如果某个命令实例的触发源是固定的(比如某个按钮绑定的命令永远是UI触发),可以直接给装饰器加一个属性来存储上下文:

修改你的分析装饰器:

public class AnyActionCommandAnalyticsDecorator : ActionCommandDecorator
{
    private readonly AnalyticsService _analyticsService = new AnalyticsService();
    
    // 新增属性,允许外部设置触发源
    public string TriggerSource { get; set; } = "Unknown";

    public AnyActionCommandAnalyticsDecorator(IActionCommand decorator) : base(decorator) { }

    public override void ExeciteAction(ActionModel actionModel)
    {
        _analyticsService.SendData(new AnalyticsModel { TriggerSource = TriggerSource });
        Decorator.ExeciteAction(actionModel);
    }
}

调用时直接设置属性:

// 绑定到UI按钮的命令,触发源固定为UIButton
var uiCommand = new AnyActionCommandAnalyticsDecorator(new AnyActionCommand())
{
    TriggerSource = "UIButton"
};
uiCommand.ExeciteAction(actionModel);

这个方案简单直接,但只适合上下文固定的场景,如果同一个命令实例需要不同的触发源,就不太适用了。


总体来说,优先选方案一,它最符合你的现有设计;如果有特殊场景限制,再考虑方案二或三。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 10:34:29