const int而不是enum的列表

时间:2011-09-08 17:26:32

标签: c# design-patterns enums

我开始研究一个大的c#代码库,发现使用了一个带有几个const int字段的静态类。这个类的行为与枚举完全相同。

我想把这个类转换成一个实际的枚举,但权力却说不了。我想转换它的主要原因是我可以将枚举作为数据类型而不是int。这对可读性有很大帮助。

有没有理由不使用枚举并使用const int代替? 目前这是代码的方式:

public int FieldA { get; set; }
public int FieldB { get; set; }

public static class Ids
{
    public const int ItemA = 1;
    public const int ItemB = 2;
    public const int ItemC = 3;
    public const int ItemD = 4;
    public const int ItemE = 5;
    public const int ItemF = 6;
}

但是,我认为应该是以下内容:

public Ids FieldA { get; set; }
public Ids FieldB { get; set; }

5 个答案:

答案 0 :(得分:6)

我认为这里的许多答案都忽略了enums语义的含义。

  • 当事先知道所有有效值(Ids)的整个集合并且小到足以在程序代码中声明时,您应该考虑使用枚举。

  • 当已知值的集合是所有可能值的子集时,您应该考虑使用int - 并且代码只需要知道此子集。

关于重构 - 当时间和业务限制允许时,当新设计/实现比先前的实现具有明显优势并且风险得到充分理解时,清理代码是个好主意。在利益低或风险高(或两者兼而有之)的情况下,采取“不伤害”的立场可能更好,而不是“持续改善” 。只有你能够判断哪种情况适用于你的情况。

顺便说一句,既不枚举常量整数的情况也是一个好主意,当ID代表外部商店中记录的标识符时(如数据库)。在程序逻辑中对这些ID进行硬编码通常是有风险的,因为这些值在不同的环境中实际上可能是不同的(例如,测试,开发,生产等)。在这种情况下,在运行时加载值可能是更合适的解决方案。

答案 1 :(得分:3)

您建议的解决方案看起来很优雅,但不会按原样运行,因为您无法使用静态类型的实例。它比模拟枚举有点棘手。

为实现选择enum或const-int有几个可能的原因,虽然我不能想到你发布的实际例子有很多强大的 - 从表面来看,它似乎是一个理想的候选者为枚举。

一些想到的想法是:

<强>枚举

  • 他们提供类型安全。您无法传递任何需要枚举值的旧数字。
  • 值可以自动生成
  • 您可以使用反射轻松转换'值'和'名称'
  • 您可以轻松枚举循环枚举中的值,然后如果添加新的枚举成员,循环将自动将它们考虑在内。
  • 如果您不小心重复了某个值,可以插入新的enunm值,而不必担心会发生冲突。

<强>常量-整数

  • 如果您不了解如何使用枚举(例如,不知道如何更改枚举的基础数据类型,或者如何为枚举值设置显式值,或者如何为多个常量指定相同的值),可能错误地认为你通过使用const来实现你不能使用枚举的东西。
  • 如果你已经习惯了其他语言,你可能会自然而然地解决问题,而不是意识到存在更好的解决方案。
  • 您可以从类派生来扩展它们,但是令人烦恼的是,您无法从现有的枚举中获取新的枚举(这将是一个非常有用的功能)。因此,你可以使用一个类(但不是你的例子!)来实现“可扩展的枚举”。
  • 你可以很容易地通过它。使用枚举可能需要您不断地将从数据库接收的数据(例如)转换为枚举类型。您在便利性方面获得的类型安全性损失。至少在你传出错误号码之前...: - )
  • 如果使用readonly而不是const,则值将存储在需要时读取的实际内存位置。这允许您将常量发布到在运行时读取和使用的另一个程序集,而不是内置到另一个程序集中,这意味着在更改自己程序集中的任何常量时,不必重新编译依赖程序集。如果您希望能够通过仅发布一个或两个程序集的更新来修补大型应用程序,这是一个重要的考虑因素。
  • 我想这是一种更清楚的方法,即枚举值必须保持不变。有了枚举,另一个程序员就会毫不犹豫地投入一个新的值,但是一系列的结果让你停下来思考“为什么会这样?我如何安全地添加新值?”。但是我通过在枚举上加上明确的值并添加一个明确的注释来实现这一点,而不是采用consts。

为什么要单独执行该实施?

  • 这段代码很可能是由一个没有充分理由的白痴写的。但改变他的代码并向他展示他是一个白痴并不是一个聪明或有帮助的举动。
  • 这可能是一个很好的理由,如果你改变它就会破坏一些东西(例如,由于通过反射访问,通过外部接口暴露,或者阻止人们轻松序列化,它可能需要成为一个类这些值因为它们会被您正在使用的混淆系统破坏。不完全理解某些东西如何工作的人不会在系统中引入不必要的错误,特别是如果他们不知道如何测试他们的变化以确保他们没有破坏任何东西。
  • 该类可以由外部工具自动生成,因此它是您需要修复的工具,而不是源代码。
  • 未来可能有计划在该课程上做更多的事情(?!)
  • 即使更改是安全的,您也必须重新测试受更改影响的所有内容。如果代码按原样运行,那么收益是否值得痛苦?在处理遗留系统时,我们经常会看到现有的质量差的代码,或者只是按照我们个人喜欢的方式完成,而且我们必须接受“修复”它并不符合成本效益,无论它有多么麻烦。当然,你也可能会发现自己咬了一口“我告诉你了!”当基于const的实现由于缺乏类型安全而失败时。但除了类型安全之外,实现最终不会比枚举更有效或更有效。

答案 2 :(得分:1)

如果没有损坏,请不要修复它。

我不知道您正在处理的系统的设计,但我怀疑这些字段是恰好恰好具有许多预定义值的整数。也就是说,在未来某个状态下,它们可能包含超过这些预定义值。虽然enum允许该场景(通过强制转换),但它意味着只有枚举包含的值才有效。

总的来说,这种变化是一种语义变化,但这是不必要的。像这样的不必要的变化通常是错误的来源,额外的测试开销和其他令人头疼的问题,只有轻微的好处。我说添加评论表示这可能是enum并保持不变。

答案 3 :(得分:0)

是的,它确实有助于提高可读性,而且我不能想出任何反对它的理由。

使用const int是C ++编程实践的一个非常常见的“旧学校”。

答案 4 :(得分:0)

我看到的原因是,如果你想与另一个使用相同常量的系统松散耦合,你就可以避免紧密耦合并共享相同的枚举类型。

就像在RPC调用中一样......