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

C#开发:如何避免带有不同依赖的switch-case语句?

解决方案:消除Switch语句,同时分离数据与行为

针对你的问题,有两种成熟的方案可以解决Switch膨胀问题,同时保持Event类(纯数据)与Engine类(业务逻辑)的解耦,符合开闭原则。


方案1:事件处理器注册表(推荐,灵活易扩展)

核心思路是给DungeonRunner维护一个事件类型-处理委托的映射字典,新增事件时只需注册对应处理器,无需修改核心遍历逻辑。

伪代码实现

public class DungeonRunner
{
    private readonly Dictionary<Type, Action<IEvent>> _eventHandlers = new();

    // 构造函数中注入引擎并注册处理器
    public DungeonRunner(ICombatEngine combatEngine, ITreasureEngine treasureEngine, ITrapEngine trapEngine)
    {
        _eventHandlers.Add(typeof(CombatEvent), e => combatEngine.Run((CombatEvent)e));
        _eventHandlers.Add(typeof(TreasureEvent), e => treasureEngine.Run((TreasureEvent)e));
        _eventHandlers.Add(typeof(TrapEvent), e => trapEngine.Run((TrapEvent)e));
        // 新增事件时,仅需在这里添加一行注册代码即可
    }

    public void RunDungeon(List<IEvent> dungeonEvents)
    {
        foreach (var dungeonEvent in dungeonEvents)
        {
            if (_eventHandlers.TryGetValue(dungeonEvent.GetType(), out var handler))
            {
                handler(dungeonEvent);
            }
            else
            {
                // 可选:处理未知事件,比如打日志警告
            }
        }
    }
}

优势

  • 完全遵循开闭原则:新增事件类型无需修改RunDungeon的循环逻辑
  • 数据与行为彻底解耦:Event类仍然是纯数据结构,不依赖任何Engine
  • 扩展性强:支持动态注册处理器(比如游戏运行时新增事件类型)

方案2:双分派模式(面向对象规范实现)

核心思路是通过IEvent的Accept方法,将自身分发到对应的处理器方法中,把类型判断逻辑从DungeonRunner转移到Event类,但仍保持Event不直接依赖Engine。

伪代码实现

首先定义核心接口:

public interface IEvent
{
    void Accept(IEventProcessor processor);
}

public interface IEventProcessor
{
    void ProcessCombatEvent(CombatEvent combatEvent);
    void ProcessTreasureEvent(TreasureEvent treasureEvent);
    void ProcessTrapEvent(TrapEvent trapEvent);
    // 新增事件时,在这里添加对应的处理方法
}

实现具体Event类(纯数据+分发逻辑):

public class CombatEvent : IEvent
{
    // 纯数据字段,比如Monster、PlayerStats等
    public void Accept(IEventProcessor processor)
    {
        processor.ProcessCombatEvent(this);
    }
}

public class TreasureEvent : IEvent
{
    // 纯数据字段,比如Loot、Gold等
    public void Accept(IEventProcessor processor)
    {
        processor.ProcessTreasureEvent(this);
    }
}

实现处理器类,绑定引擎与事件逻辑:

public class DungeonEventProcessor : IEventProcessor
{
    private readonly ICombatEngine _combatEngine;
    private readonly ITreasureEngine _treasureEngine;
    private readonly ITrapEngine _trapEngine;

    public DungeonEventProcessor(ICombatEngine combatEngine, ITreasureEngine treasureEngine, ITrapEngine trapEngine)
    {
        _combatEngine = combatEngine;
        _treasureEngine = treasureEngine;
        _trapEngine = trapEngine;
    }

    public void ProcessCombatEvent(CombatEvent combatEvent)
    {
        _combatEngine.Run(combatEvent);
    }

    public void ProcessTreasureEvent(TreasureEvent treasureEvent)
    {
        _treasureEngine.Run(treasureEvent);
    }

    public void ProcessTrapEvent(TrapEvent trapEvent)
    {
        _trapEngine.Run(trapEvent);
    }
}

最后修改DungeonRunner:

public class DungeonRunner
{
    private readonly IEventProcessor _eventProcessor;

    public DungeonRunner(IEventProcessor eventProcessor)
    {
        _eventProcessor = eventProcessor;
    }

    public void RunDungeon(List<IEvent> dungeonEvents)
    {
        foreach (var dungeonEvent in dungeonEvents)
        {
            dungeonEvent.Accept(_eventProcessor);
        }
    }
}

优势

  • 类型安全:无需as或强制类型转换,编译时即可检查类型匹配
  • 符合面向对象设计规范:将事件分发逻辑封装在对应Event类中
  • 同样遵循开闭原则:新增事件仅需扩展接口和实现类

方案选择建议

  • 如果是快速迭代的小型项目,优先选注册表方案,代码更简洁,扩展成本更低
  • 如果需要更严谨的架构设计,或者团队更倾向于面向对象规范,选双分派模式

内容的提问来源于stack exchange,提问作者ConnieMnemonic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 16:40:16