1

I'm trying to create a base class that works like a state machine and that can accept any type of enum:

 public class BaseFSM <T> where T : struct, IConvertible { //Basic class that denote the transition between one state and another public class StateTransition { public T currentState { get; set; } public T nextState { get; set; } //StateTransition Constructor public StateTransition(T currentState, T nextState) { this.currentState = currentState; this.nextState = nextState; } public override int GetHashCode() { return 17 + 31 * this.currentState.GetHashCode() + 31 * this.nextState.GetHashCode();; } public override bool Equals(object obj) { StateTransition other = obj as StateTransition; return other != null && this.currentState as Enum == other.currentState as Enum && this.nextState as Enum == other.nextState as Enum; } } protected Dictionary<StateTransition, T> transitions; //All the transitions inside the FSM public T currentState; public T previusState; protected BaseFSM() { // Throw Exception on static initialization if the given type isn't an enum. if(!typeof (T).IsEnum) throw new Exception(typeof(T).FullName + " is not an enum type."); } private T GetNext(T next) { StateTransition transition = new StateTransition(currentState, next); T nextState; if (!transitions.TryGetValue(transition, out nextState)) throw new Exception("Invalid transition: " + currentState + " -> " + next); return nextState; } } 

As you can see I defined both GetHashCode() and Equals(object obj). This is my implementation of my child class:

public class FSMPlayer : BaseFSM<PlayerState> { public FSMPlayer() : base() { this.currentState = PlayerState.Idle; this.transitions = new Dictionary<StateTransition, PlayerState> { { new StateTransition(PlayerState.Idle, PlayerState.Run), PlayerState.Run }, //0 { new StateTransition(PlayerState.Run, PlayerState.Jump), PlayerState.Jump }, //1 }; } } 

As you can see in my child class I'm using my PlayerState Enum to define the state transitions. The problem it's when I try to use the getNext function because the TryGetValue always return false. The GetHashCode functions seams to work very well so I can't understand where the problem is. Thanks.

2 Answers 2

3

The problem is here:

this.currentState as Enum == other.currentState as Enum 

Enum is a reference type, so your enum gets boxed into a (new, unique) object. As a result it no longer compares equal to any other boxed instance.

enum types do the Right Thing for overriding Equals, though (as @hvd so correctly points out), so you can just do

this.currentState.Equals(other.currentState) 
Sign up to request clarification or add additional context in comments.

3 Comments

Wouldn't a simple this.currentState.Equals(other.currentState) work?
@hvd: yes, absolutely, I'm being silly. (Also, enums don't implement IComparable<T>, but they do implement IComparable.) If you want to post this as an answer yourself, I'll delete mine.
You did identify the real problem, and you did post a valid way of solving it. I'm happy to just keep your answer. :)
0

You may also want to read the answers to this question to see why calling getHashCode on an enum is not recommended.

Using GetHashCode for getting Enum int value

1 Comment

This is perfectly fine. The answer in that question discusses why you should not rely on GetHashCode() to return the numerical value of the enum. If you are actually using it to hash it (and so not relying on that property at all), there's no problem.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.