在switch语句中针对枚举进行编程,这是你的方法吗?

看一下代码片段:

这是我在编写枚举时通常所做的事情。 我有一个带有InvalidOperationException的默认转义(我不使用ArgumentException或它的一个派生,因为编码是针对私有实例字段而不是传入参数)。

我想知道你们的开发人员是否也编写了这个逃避的想法….

public enum DrivingState {Neutral, Drive, Parking, Reverse}; public class MyHelper { private DrivingState drivingState = DrivingState.Neutral; public void Run() { switch (this.drivingState) { case DrivingState.Neutral: DoNeutral(); break; case DrivingState.Drive: DoDrive(); break; case DrivingState.Parking: DoPark(); break; case DrivingState.Reverse: DoReverse(); break; default: throw new InvalidOperationException( string.Format(CultureInfo.CurrentCulture, "Drivestate {0} is an unknown state", this.drivingState)); } } } 

在代码审查中,我遇到了许多在默认转义中只有break语句的实现。 这可能是一个问题随着时间的推移….

我不喜欢这种方法,因为默认情况是不可测试的。 这导致你的unit testing的覆盖率降低,虽然不一定是世界的末日,但我却厌倦了强迫症。

我更愿意简单地对每个案例进行unit testing,并且还有一个额外的断言,即只有四种可能的情况。 如果有人添加了新的枚举值,unit testing就会中断。

就像是

 [Test] public void ShouldOnlyHaveFourStates() { Assert.That(Enum.GetValues( typeof( DrivingState) ).Length == 4, "Update unit tests for your new DrivingState!!!"); } 

你的问题有点模糊,但据我了解,你问我们你的编码风格是否合适。 我通常根据它的可读性来判断编码风格。

我读了一次代码,我明白了。 所以,在我看来,你的代码是良好编码风格的一个例子。

还有一个替代方案,就是使用与Java的枚举类似的东西。 私有嵌套类型允许“更严格”的枚举,其中编译时唯一可用的“无效”值为null 。 这是一个例子:

 using System; public abstract class DrivingState { public static readonly DrivingState Neutral = new NeutralState(); public static readonly DrivingState Drive = new DriveState(); public static readonly DrivingState Parking = new ParkingState(); public static readonly DrivingState Reverse = new ReverseState(); // Only nested classes can derive from this private DrivingState() {} public abstract void Go(); private class NeutralState : DrivingState { public override void Go() { Console.WriteLine("Not going anywhere..."); } } private class DriveState : DrivingState { public override void Go() { Console.WriteLine("Cruising..."); } } private class ParkingState : DrivingState { public override void Go() { Console.WriteLine("Can't drive with the handbrake on..."); } } private class ReverseState : DrivingState { public override void Go() { Console.WriteLine("Watch out behind me!"); } } } 

这看起来很合理。 还有一些其他选项,比如Dictionary ,但是你拥有的更简单,并且应该足以满足大多数简单的情况。 总是喜欢简单易读;-p

这可能是主题,但也许不是。 检查必须存在的原因是设计发展并且您必须向枚举添加新状态。

所以也许你不应该首先以这种方式工作。 怎么样:

 interface IDrivingState { void Do(); } 

将当前状态(实现IDrivingState的对象)存储在变量中,然后执行它,如下所示:

 drivingState.Do(); 

据推测,你可以通过某种方式让一个国家过渡到另一个州 – 也许Do会回归新州。

现在,您可以扩展设计,而不会使所有现有代码失效。

更新以回应评论:

通过使用enum / switch ,当您添加新的枚举值时,您现在需要在代码中找到尚未处理该枚举值的每个位置。 编译器不知道如何帮助它。 代码的各个部分之间仍然存在“契约”,但编译器检查它是隐含的,也是不可能的。

多态方法的优点是设计更改最初会导致编译器错误。 编译错误很好! 编译器有效地为您提供了需要修改的代码中的位置清单,以应对设计更改。 通过这种方式设计代码,您可以获得强大的“搜索引擎”的帮助,该搜索引擎能够理解您的代码并通过在编译时发现问题来帮助您进化,而不是将问题留到运行时。

我会使用NotSupportedException

NotImplementedException用于未实现的function,但实现了默认情况。 你只是选择不支持它。 我只建议在开发期间为存根方法抛出NotImplementedException。

如果你想抛出exception,我建议使用NotImplementedException或更好的自定义DrivingStateNotImplementedException。

我,我会默认使用默认的驾驶状态(如中立/停止)并记录缺少的驾驶员(因为这是你错过了驾驶状态,而不是客户)

它就像一辆真正的汽车,cpu决定它不能打开灯,它做什么,抛出exception并“中断”所有控制,或者回到一个安全的已知状态并向驾驶员发出警告“oi ,我没有灯“

如果您遇到未处理的枚举值,您应该怎么做取决于具体情况。 有时只处理一些值是完全合法的。

如果你有一个unhandles值是一个错误,你肯定会像在示例中那样抛出一个exception(或以其他方式处理错误)。 人们不应该在没有出现错误迹象的情况下吞下错误条件。

一个只有break default情况并不是很好。 我会删除它以指示交换机不处理所有值,并可能添加注释解释原因。

清晰,明显和正确的方法。 如果DrivingState需要改变,您可能需要重构。

上面所有复杂的多态恐怖的问题是它们强制封装成一个类或者需要额外的类 – 当只有一个DrivingState.Drive()方法时它很好但是只要你有一个DrivingState.Serialize()就会中断整个事情。序列化到依赖于DrivingState或任何其他真实条件的某个地方的方法。

枚举和开关是相互制作的。

我是C程序员,而不是C#,但是当我有这样的东西时,如果不是所有枚举案例都在交换机中处理,我的编译器设置就会发出警告。 设置之后(并设置warnings-as-errors),我不打扰运行时检查可以在编译时捕获的内容。

这可以在C#中完成吗?

我从不使用开关。 类似于你所展示的代码在我使用的大多数框架中总是一个主要的痛点 – 不可扩展并固定到有限数量的预定义案例。

这是一个很好的例子,可以用简单的多态性以一种漂亮,干净和可扩展的方式完成。 只需声明一个基础DrivingStrategyDrivingStrategyinheritance所有版本的驱动逻辑。 这不是过度工程 – 如果你有两种情况,但有四种已经表明需要,特别是如果每​​个版本的Do …都调用其他方法。 至少这是我个人的经历。

我不同意冻结许多州的Jon Skeet解决方案,除非这确实是必要的。

我认为使用枚举类型并因此切换语句来实现State(也是State Design Pattern) 并不是一个特别好的主意。 恕我直言,这是容易出错的。 随着正在实现的状态机变得复杂,代码将逐渐降低您的程序员的可读性。

目前它非常干净,但不知道这个枚举的确切意图,很难说它会如何随着时间的推移而发展。

另外,我想在这里问你 – 有多少操作适用于DrivingState以及Run()? 如果有几个,如果你基本上会多次复制这个switch语句,那么至少可以说它会让人觉得有问题的设计。