C#中的私有值标记枚举

Sco*_*ner 6 c# enums flags design-patterns

我在C#中创建了一个标志枚举,类似于以下内容:

    [Flags]
    public enum DriversLicenseFlags
    {
        None = 0,

        Suspended = 1 << 1,
        Revoked   = 1 << 2,

        Restored  = 1 << 3,
        SuspendedAndRestored = Suspended | Restored,
        RevokedAndRestored   = Revoked   | Restored,
    }
Run Code Online (Sandbox Code Playgroud)

关于我的意图的一些注意事项:

  • Suspended并且Revoked是可以但不一定导致恢复的独特状态.
  • Restored应该只有在用户已经SuspendedRevoked(或两者都有)的情况下才有可能.重要的是要具体跟踪哪个事件是恢复的前兆.
  • 许可证可以是SuspendedRevoked(和Restored)

另外,我试图坚持在MSDN的Designing Flags Enumerations中提出的建议.特别是:

  • 考虑为常用的标志组合提供特殊的枚举值.
    • SuspendedAndRestored并且RevokedAndRestored两者都很常见.
  • 当某些值组合无效时,请避免创建标志枚举.
    • 这是我的问题,因为Restored除非至少有一个是无效的Suspended,并Revoked设置.

理想情况下,我希望Restored在内部使用的枚举中存在一个值,但只能通过某些有效组合公开设置.不幸的是,internal它不是枚举值的有效修饰符.

我想过几个选择,但每个似乎都有缺点:

  1. 保留Restored作为公共值,请注意注释中的限制,并对公共API上的无效组合进行前置条件检查.

    这可行,并且很可能是我将采用的解决方案.但是,似乎他们应该是一个更清洁的解决方案.

  2. 使用这里描述的增强的类似java的枚举并定义Restoredinternal static.

    这也可行,但感觉有点矫枉过正,因为此时我不需要任何其他功能.

  3. 不要定义Restored为值,而是保留OR的值,并检查使用方法中的值.即:

    internal const int RestoredFlag = 1 << 3;
    [Flags]
    public enum DriversLicenseFlags
    {
        None = 0,
    
        Suspended = 1 << 1,
        Revoked   = 1 << 2,
    
        SuspendedAndRestored = Suspended | RestoredFlag,
        RevokedAndRestored   = Revoked   | RestoredFlag,
    }
    
    Run Code Online (Sandbox Code Playgroud)

无论是如何定义以及如何在内部使用它,这都让我觉得很烦.

Jon*_*Jon 2

为什么要Flags专门使用呢?这不正是您所追求的吗?

public enum DriversLicenseStatus
{
    None = 0,
    Suspended,
    Revoked,
    SuspendedAndRestored,
    RevokedAndRestored,
}
Run Code Online (Sandbox Code Playgroud)

确保仅从属性的属性设置器内进行“有效”转换当然很容易DriversLicenseStatus

如果出于某种原因您确实想Flags在内部使用,那么您可以定义一个单独的对象private enum DriversLicenseStatusFlags并从中转换为仅DriversLicenseStatus在公共接口中公开值。

另一个值得考虑的选择是将枚举分为两个值:

bool IsActive;

enum InactiveReason {
    None = 0,
    Suspended,
    Revoked,
}
Run Code Online (Sandbox Code Playgroud)

“AndRestored”案例是带有IsActive == true和 的案例InactiveReason != InactiveReason.None

我的明显印象是你在这里过度设计了。:)