是否可以在 C# 中限制公共枚举值?

Posted

技术标签:

【中文标题】是否可以在 C# 中限制公共枚举值?【英文标题】:Is it possible to restrict public enum values in C#? 【发布时间】:2017-12-24 22:35:15 【问题描述】:

我目前正在编写一个由展品组成的巡演软件程序。展览对象在任何给定点都处于由 ExhibitStates 枚举定义的四种状态之一:

private enum ExhibitState  Ready, Active, Complete, Inactive ;

对于将要设置展览的开发者,我希望他们能够选择的只有两种“开始”状态:

public enum StartingExhibitState  Ready, Inactive ;

目前,我对其进行了设置,以便在初始化后,展览将立即设置其状态以匹配其起始状态,如下所示:

        switch (startingState) 
            case StartingExhibitState.Ready:
                SetState(ExhibitState.Ready);
                break;
            case StartingExhibitState.Inactive:
                SetState(ExhibitState.Inactive);
                break;
        

我发现自己今天想知道这是否是最佳做法。有没有更好的方法来限制哪些枚举选项是公共的,哪些是私有的?还是最好简单地拥有两个单独的枚举?

非常感谢您的宝贵时间。

【问题讨论】:

限制类中枚举值的“设置”不是更容易吗? 你的 switch 语句的设置方式,你可以简单地一次设置状态,或者设置一次你不想使用的情况,一次打破它们,然后设置默认动作中的状态。我还假设一个状态是否真的可以从非活动状态切换到完成状态是有逻辑的? 您可以默认为Inactive 并提供SetReady 方法,完全不需要传递起始状态。 【参考方案1】:

如果您创建第二个枚举 - 您的意图将通过设置方法的签名非常清楚地解释

public enum ExhibitState 
 
    Inactive = 0,
    Active = 1,
    Ready = 2,
    Complete = 3
;

public enum InitialStates 
 
    Inactive = ExhibitState.Inactive,
    Ready = ExhibitState.Ready
;

public void SetInitial(InitialStates state)

    SetState((ExhibitState)state);

如果你走得更远,你可以添加编译器帮助以防止向方法传递错误的值。

public sealed class InitialState

    public static readonly InitialState Initial = new InitialState(ExhibitState.Initial);

    public static readonly InitialState Ready = new InitialState(ExhibitState.Ready);

    public ExhibitState State  get;             

    private InitialState(ExhibitState state)
    
        State = state;
    

构造函数创建private 以防止从其他地方实例化类。 标记为 sealed 的类以防止派生和更改其行为。

那么你的方法会是这样的

public void SetInitial(InitialState start)

    SetState(start.State);
  

// use it
SetInitial(InitialState.Initial);
SetInitial(InitialState.Ready);

在你更改InitialState 类的代码之前,没有其他的可以通过。

【讨论】:

您的枚举值不匹配。您应该声明public enum InitialStates Ready, Inactive = 3 ;,否则InitialStates.Inactive 将被映射到ExhibitState.Active 你可以显式:public enum InitialStates Ready = ExhibitState.Ready, Inactive = ExhibitState.Inactive ; 这就是我目前正在做的事情。我想知道这是否是最好的方法,或者是否有更简单的方法。我想这是要走的路。谢谢【参考方案2】:

您可以使用基于类的方法,而不是使用枚举(或其中两个):

public abstract class ExhibitState 

    public static ExhibitInitialState Ready  get  return new ExhibitReadyState();  
    public static ExhibitInitialState Inactive  get  return new ExhibitInactiveState();  
    public static ExhibitState Complete  get  return new ExhibitCompleteState();  
    public static ExhibitState Active  get  return new ExhibitActiveState();  

    private class ExhibitReadyState : ExhibitInitialState 
    private class ExhibitInactiveState : ExhibitInitialState 
    private class ExhibitCompleteState : ExhibitState 
    private class ExhibitActiveState : ExhibitState 


public abstract class ExhibitInitialState : ExhibitState 

上面的示例显示了一个简单的方法。通常,您不会在 get 方法中创建状态的新实例,而是使用静态实例以便比较。

类似于枚举,您仍然可以输入ExhibitState.Ready 或其他状态。此外,基类ExhibitInitialState 允许您限制初始可设置的状态:

public void SetInitial(ExhibitInitialState initState)  ... 

与@Fabio 提出的方法相比,您的好处是不能混淆这些值。此外,与状态特别相关:行为也应该针对特定状态发生变化是很常见的。使用这种基于类的方法,您可以在特定的 ExhibitState 实现中实现此行为,从而避免在基于枚举的方法中可能存在的大量 switch 语句。

【讨论】:

如果你走这条路,请考虑不要每次都创建状态子类的新实例。您可以使用 C# 6 的新语言特性(只读自动属性)每次从此类 public static ExhibitInitialState Ready get ; = new ExhibitReadyState(); 获取相同的实例。这将使通过相等性检查比较状态变得更容易,而不必弄乱相等性和散列。 @BradleyUffner 是的,你是对的。我只是想让示例简短而简单。

以上是关于是否可以在 C# 中限制公共枚举值?的主要内容,如果未能解决你的问题,请参考以下文章

是否可以限制用户在 C# 中拍摄屏幕快照

C#泛型 类型约束

api 文档和“价值限制”:它们匹配吗?

我可以使用打字稿将对象键限制为枚举值吗?

如何限制Objective C中枚举值的可见性?

可以将泛型类型限制为枚举吗? [复制]