自定义字典 TryGetValue 找不到键
Custom Dictionary TryGetValue doesn't find keys
我正在尝试创建一个像状态机一样工作并且可以接受任何类型的枚举的基础 class:
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;
}
}
如您所见,我同时定义了 GetHashCode() 和 Equals(object obj)。这是我对 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
};
}
}
正如您在我的 child class 中看到的那样,我正在使用我的 PlayerState 枚举来定义状态转换。问题出在我尝试使用 getNext 函数时,因为 TryGetValue 总是 return false。 GetHashCode 函数接缝工作得很好,所以我不明白问题出在哪里。
谢谢
您可能还想阅读此问题的答案,了解为什么不建议对枚举调用 getHashCode。
Using GetHashCode for getting Enum int value
问题出在这里:
this.currentState as Enum == other.currentState as Enum
Enum
是引用类型,因此您的枚举被装箱到一个(新的,唯一的)对象中。因此,它不再与任何其他盒装实例进行比较。
enum
类型为覆盖 Equals
做了正确的事情(正如@hvd 正确指出的那样),所以你可以做
this.currentState.Equals(other.currentState)
我正在尝试创建一个像状态机一样工作并且可以接受任何类型的枚举的基础 class:
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;
}
}
如您所见,我同时定义了 GetHashCode() 和 Equals(object obj)。这是我对 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
};
}
}
正如您在我的 child class 中看到的那样,我正在使用我的 PlayerState 枚举来定义状态转换。问题出在我尝试使用 getNext 函数时,因为 TryGetValue 总是 return false。 GetHashCode 函数接缝工作得很好,所以我不明白问题出在哪里。 谢谢
您可能还想阅读此问题的答案,了解为什么不建议对枚举调用 getHashCode。
Using GetHashCode for getting Enum int value
问题出在这里:
this.currentState as Enum == other.currentState as Enum
Enum
是引用类型,因此您的枚举被装箱到一个(新的,唯一的)对象中。因此,它不再与任何其他盒装实例进行比较。
enum
类型为覆盖 Equals
做了正确的事情(正如@hvd 正确指出的那样),所以你可以做
this.currentState.Equals(other.currentState)