在 C# 中覆盖派生 class 中的枚举

override enum in derived class in C#

我正在创建一个 abstract 有限机器状态 class 和一个 enum 用于它可以接收的可能命令,例如:

public abstract class FSMBase
{
    public enum Commands {};
    public enum States;
    public Dictionary<Transition, States> AvailableTransitions;
    public States CurrentState;

    public abstract void InitCommandsAndStatesAndTransitiosnAndInitialState();

    public void ProcessCommand(Commands _command)
    {
        Transition RequestedTransition = new Transition(CurrentState, command);
        if(AvailableTransitions.TryGetValue(RequestedTransition, out State nextState) //pseudocode
        {
             CurrentState = nextState;
        }
    }
}

然后在派生的 class 中,我想 覆盖 StatesTransitionsCommands。类似于:

public class MyFSM : FSMBase
{
    public override void InitCommandsAndStatesAndTransitiosnAndInitialState()
    {
        States = {Off, starting, started, ...} //HERE IS MY PROBLEM
        Commands = {start, stop, finish, ...}; // HERE IS MY PROBLEM

        Transitions = new Dictionary<Transition, BaseState>
        {
            {new Transition(States.Off, Commands.Start), States.starting},
            ....
        }

        CurrentState = States.Off;
    }
}

如何覆盖派生的class中的enum???

好吧,enum 实际上是 intbyteshortlong 等等)并且不能被覆盖。我建议改用 generics

public abstract class FSMBase<State, Command> 
  where State   : Enum  // : Enum wants C# 7.3+
  where Command : Enum {

  //TODO: I suggest have these fields private, or at least, protected
  public Dictionary<Transition, State> AvailableTransitions;
  public State CurrentState;

  public void ProcessCommand(Command _command) {
    ...
  }

}

实施 MyFSM 时,您可以放置​​所需的枚举:

public class MyFSM : FSMBase<MyStates, MyCommands> {
  ...
}

编辑: 如果是 较低的 c# 版本,您可以尝试相同的想法但不同的约束:

public abstract class FSMBase<State, Command> 
  where State   : struct  
  where Command : struct {

  public State CurrentState;
  ...        

  // Instead of compile time error we are going to have runtime one,
  // if either State or Command is not enum
  static FSMBase() {
    if (!typeof(State).IsEnum)
      throw new InvalidCastException("Generic pararameter State must be enum!");
    else if (!typeof(Command).IsEnum)
      throw new InvalidCastException("Generic pararameter Command must be enum!");
  }
}

...

public class MyFSM : FSMBase<MyStates, MyCommands> {
  public override void InitCommandsAndStatesAndTransitiosnAndInitialState() {
    ...
    CurrentState = MyStates.Off;
    ... 
  }
  ...
}