Пользовательский словарь TryGetValue не находит ключи

57
7

Я пытаюсь создать базовый класс, который работает как конечный автомат и может принимать любой тип перечисления:

    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 (объект obj). Это моя реализация моего дочернего класса:

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
};
}
}

Как вы можете видеть в моем дочернем классе, я использую свой PlayerState Enum для определения переходов состояния. Проблема в том, что когда я пытаюсь использовать функцию getNext, потому что TryGetValue всегда возвращает false. Функция GetHashCode работает хорошо, поэтому я не могу понять, где проблема. Благодарю.

спросил(а) 2015-02-22T16:56:00+03:00 5 лет, 7 месяцев назад
1
Решение
80

Проблема здесь:

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

Enum является ссылочным типом, поэтому ваш enum получает коробку в (новый, уникальный) объект. В результате он больше не сравнивается с любым другим экземпляром в коробке.

enum типы делают правильную вещь для переопределения Equals, хотя (как правильно указывает @hvd), так что вы можете просто сделать

this.currentState.Equals(other.currentState)

ответил(а) 2015-02-22T17:10:00+03:00 5 лет, 7 месяцев назад
40

Вы также можете прочитать ответы на этот вопрос, чтобы узнать, почему вызов getHashCode в перечислении не рекомендуется.

Использование GetHashCode для получения значения Enum int

ответил(а) 2015-02-22T17:10:00+03:00 5 лет, 7 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема