【问题标题】:List of const int instead of enumconst int 而不是 enum 的列表
【发布时间】:2011-09-08 17:26:32
【问题描述】:

我开始编写大型 C# 代码库,发现使用带有多个 const ints 字段的静态类。这个类的行为与枚举完全一样。

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

有什么理由不使用枚举而使用 const ints 吗? 目前的代码是这样的:

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; }

【问题讨论】:

  • 使用数据类型而不是 int 还可以防止编译器发现任何可能的错误。
  • 在不知道这些字段和常量的用途的情况下,很难找到一个合理的答案来提供高质量、具体的架构建议。
  • 你为什么不问“权力是什么”?

标签: c# design-patterns enums


【解决方案1】:

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

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

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

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

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

【讨论】:

  • +1。这可能是最完整的答案,无需了解这些字段的使用方式。
  • 我在代码中看到的核心问题是数据类型在几个地方都是int,而实际上它应该是枚举值。因此,将来传入无效值时,我可以看到很大的问题。
  • @Telavian:正如我所说,如果有一组已知的值代表这些字段唯一可能的有效值,那么enum 可能是要走的路。但是如果某些值可以在运行时获取并传入,那么枚举可能不是您想要的。
【解决方案2】:

您建议的解决方案看起来很优雅,但不能按原样工作,因为您不能使用静态类型的实例。比模拟枚举要复杂一些。

为实现选择 enum 或 const-int 有几个可能的原因,尽管对于您发布的实际示例,我想不出很多强有力的原因 - 从表面上看,它似乎是一个理想的候选者一个枚举。

脑海中浮现的一些想法是:

枚举

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

常量整数

  • 如果您不了解如何使用枚举(例如,不知道如何更改枚举的基础数据类型,或者如何为枚举值设置显式值,或者如何为多个常量分配相同的值),您使用 const 可能会错误地认为您正在实现无法使用枚举的目标。
  • 如果您习惯了其他语言,您可能会很自然地使用 const 解决问题,而没有意识到存在更好的解决方案。
  • 您可以从类派生来扩展它们,但令人讨厌的是,您不能从现有的枚举中派生新的枚举(这将是一个非常有用的功能)。因此,您可能会使用一个类(但不是您的示例!)来实现“可扩展枚举”。
  • 您可以轻松地传递整数。使用枚举可能需要您不断地将(例如)从数据库接收到的数据转换为枚举类型和从枚举类型中接收。你在类型安全中失去的东西,你在便利中获得。至少直到你在某处传递了错误的号码...... :-)
  • 如果使用 readonly 而不是 const,则值将存储在实际内存位置中,需要时读取。这允许您将常量发布到在运行时读取和使用的另一个程序集,而不是内置到另一个程序集中,这意味着当您更改自己程序集中的任何常量时,您不必重新编译依赖程序集。如果您希望仅通过发布一两个程序集的更新来修补大型应用程序,这是一个重要的考虑因素。
  • 我想这是一种更清楚地说明枚举值必须保持不变的方法。使用枚举,另一个程序员会不假思索地输入一个新值,但是一个 const 列表会让你停下来思考“为什么会这样?我如何安全地添加一个新值?”。但我会通过在枚举上添加明确的值并添加明确的注释来实现这一点,而不是诉诸于 const。

为什么要不理会实施?

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

【讨论】:

    【解决方案3】:

    如果它没有坏,就不要修理它。

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

    总体而言,更改是语义上的,但没有必要。像这样不必要的更改通常会导致错误、额外的测试开销和其他令人头疼的问题,而这些好处只有轻微的好处。我说添加一条评论,表示这可能是 enum 并保持原样。

    【讨论】:

    • 如果它没有损坏,不要修复它会导致技术债务。我同意这里有利有弊,但我不知道您如何才能对权衡做出判断。
    • @David:如果它是一个大型代码库,我预计会有很多技术债务。这不是导致它,它已经存在。但是,选择花精力修复这是一个很大的选择,而且根据我的经验,永远不会超过花钱修复错误和新功能的需要。更改此代码可能(并且不能保证)修复一小部分技术债务,但很容易破坏很多 - 这是一个昂贵的决定。没有在问题中提出任何令人信服的理由,我通过了我的判断并且我支持它。
    • 如果您因为害怕引入错误而无法进行此更改,那么您需要更好的测试。如果您的测试无法解决这个问题,那么您的技术债务将会迅速增加。
    • @David:这与测试能否应对它无关。即使更改简单的代码也会产生无法预料的后果。有了给定的信息(例如大型代码库),我想说即使是很小的变化也可能是危险的。从这里告诉我们的内容来看,这是不必要的,因此应该避免。 100% 的测试覆盖率会很棒,但这并不常见 - 如果你发明了 100% 无错误的开发方法,你应该很快变得富有和成名。
    • @David:我同意,但据我们所知,OP 对系统并不了解,但我们可能会假设“权力”有,他们说“不,不要改变它”。此外,恐惧并不是唯一起作用的因素。做出这种改变仍然需要预算。
    【解决方案4】:

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

    使用 const int 是 C++ 编程实践中非常常见的“老派”。

    【讨论】:

      【解决方案5】:

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

      就像在 RPC 调用什么的......

      【讨论】:

      • 您只需将enum 转换为int 即可进行这些调用。这不是不在一个应用程序中使用 enum 的理由。
      • 如果 rpc 或低级调用返回一个 int,实际上您可以在“程序空间”中使用枚举。事实上,如果两个实体相互交谈不同步,它会更清楚,它会中断。它是双向的,不仅将 your 枚举转换为 int,而且将您收到的 int 转换为枚举。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-16
      • 1970-01-01
      相关资源
      最近更新 更多