【问题标题】:Enums and case statements枚举和案例陈述
【发布时间】:2011-10-20 06:57:47
【问题描述】:

如果我们应该尝试避免 switch/case 语句以及如何为枚举执行此操作,以及如何建议如何,请考虑以下示例,我正在寻找充分的理由: (请注意,此开关/案例可能分散在整个代码库中)

switch (theEnum)
{
    case MyEnum.Enum1:
        // dosomething
    case MyEnum.Enum2:
        // do something
    case MyEnum.Enum3:
        // do something
    default:
       throw new Exception("Unsupported enumeration: " + theEnum.ToString());

}

对比

public Dictionary<MyEnum, StrategyBase> BuildMapper()
{
    var mapper = new Dictionary<MyEnum, StrategyBase>();
    mapper[MyEnum.Enum1] = new Strategy1();
    mapper[MyEnum.Enum2] = new Strategy2();
    mapper[MyEnum.Enum3] = new Strategy3();
return mapper;
}

BuildMapper()[MyEnum.Enum1].DoSomething();

选项 2 更加面向对象,但我想知道其他人如何看待这种方法,以及是否有充分和令人信服的理由让我们努力这样做。

例如,有人可能会争辩说 switch/else 等原则会违反 open-close。

【问题讨论】:

  • 如果您专注于 Cyclometric 复杂性并且方法总是需要可扩展,那么 OO 方法会更好。
  • 需要注意的是,交换机的执行速度要快得多。遍历列表也将比使用字典更快,除非您的字典中有大约 10 个或更多项。

标签: c# design-patterns


【解决方案1】:

对于 OO,您应该使用 Visitor Pattern

【讨论】:

  • 您能否详细说明为什么应该使用访问者模式,并且认为它可以替代简单的 switch/case 语句,因为恕我直言,这些语句似乎有点矫枉过正。
  • 实际上我喜欢这个想法,访问者可能需要额外的管道,但是比策略更好的地方是策略需要为每个枚举和每个操作创建一个类,其中访问者将是一个类一组操作(更易于维护)
  • 有一种方法可以通过使用反射将枚举映射到方法来自动执行双重调度,这种方式的缺点是动态性质意味着编译器不会检测到枚举的重大更改,但是,您可能会想出一个属性来表示方法之上的枚举,然后您将获得编译器的帮助
【解决方案2】:

我会将BuildMapper 设为静态(也是只读的),因为它总是会返回相同的字典集。

至于为什么这很好,原因应该很简单,当您有一个设计时事物从一个事物映射到另一个事物并且这种映射将始终是静态的,很明显将其表示为字典而不是 if/ else 或 switch case 隐藏了它只是一个映射的意图。

【讨论】:

    【解决方案3】:

    如果它只是在一两个地方,我会选择切换。如果如您所说,“此开关/案例可能分散在整个代码库中”,请选择第二种解决方案。

    这不仅是更多的面向对象,这很好,而且在您的情况下更易于维护。在这种情况下,对性能和内存消耗的担忧完全无关紧要,首先考虑易于维护并在需要时进行优化(但我认为您永远不需要优化 this)。

    在这种情况下,可读性损失也无关紧要 - 了解第二种方法的作用需要很少的时间。

    【讨论】:

      【解决方案4】:

      我认为第一个变体更好,因为它看起来更具可读性和明确性。

      【讨论】:

        【解决方案5】:

        我想说这一切都取决于您想要实现的目标。第一个示例更容易阅读,如果您与他人共享您的代码库,这一点很重要。如果您遵循某种模式,BuilderMapper 可能会很有用

        【讨论】:

          【解决方案6】:

          我猜你是在比较橘子和苹果。

          切换是一个变量和几个常量数据之间的顺序比较。除非你有一个 1K-cases switch,否则它应该比 Dictionary 更有效。

          当然,与 Dictionary 这样非常复杂的对象相比,开关消耗的内存要少得多。

          最后,枚举不限于声明的选项,而是可以组合为“标志”。使用 hashmap 将无法使用此功能。

          满意吗?

          【讨论】:

          • 你提到的性能问题是一个好点,但是我们谈论 10 微秒的性能是多少?我不知道,但对于 99% 的业务线应用程序来说可能可以忽略不计。使用枚举作为“标志”也是正确的,但总是可以在策略类中组成实际的枚举值?
          • 确实如此。关于这个问题,我只有两点:(1)switch 让您能够通过从一个案例“跳转”到另一个案例来免费组合,以及(2)switch 是一种命令式方法,而 hashmap 是功能性的.没有其他线索!...
          • 对不起,我没有回答你...枚举的基础类型是整数。因此,您可以使用枚举的任何组合,只要您不会破坏类型安全。顺便说一句,枚举不是价值安全的!
          猜你喜欢
          • 1970-01-01
          • 2014-09-28
          • 2021-01-01
          • 1970-01-01
          • 2023-04-10
          • 2010-10-30
          • 2016-05-13
          • 2016-02-21
          • 1970-01-01
          相关资源
          最近更新 更多