Общая подпись для типов Enum - PullRequest
1 голос
/ 26 апреля 2011

В моем проекте определено несколько типов Enum, используемых для идентификаторов состояния объекта:

  public enum ObjectAState
  {
    ObjectAAvailable,
    ObjectADeleteRequested,
    ObjectADeleted
  }
  public enum ObjectBState
  {
    ObjectBCreationRequested,
    ObjectBCreationFailed,
    ObjectBDeleteRequested,
    ObjectBDeleted
  }

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

Для данного состояния могут быть ноль, одно или много других состояний (в пределах того же enum), которые могут следовать; по определению, существуют также определенные состояния, которые не могут следовать. Например, в ObjectA состояние может переходить с ObjectAAvailable на ObjectADeleteRequested и с ObjectADeleteRequested на ObjectADeleted, но не напрямую с ObjectAAvailable на ObjectADeleted. В каждом объекте есть утомительный и повторяющийся фрагмент кода для принудительного выполнения допустимых переходов состояний, который я хочу заменить одним методом.

В качестве теста я сделал это:

Dictionary<ObjectAState, List<ObjectAState>> Changes = new Dictionary<ObjectAState, List<ObjectAState>>();

Это Dictionary, доступ к которому осуществляется через ключ ObjectAState, содержащий List других ObjectAState значений, которые указывают действительные переходы, заполненные таким образом:

Changes.Add(ObjectAState.ObjectAAvailable, new List<ObjectAState> { ObjectAState.ObjectADeleteRequested });
Changes.Add(ObjectAState.ObjectAADeleteRequested, new List<ObjectAState> { ObjectAState.ObjectADeleted });
Changes.Add(ObjectAState.ObjectADeleted, null);

И у меня есть метод, который выглядит просто так:

public bool StateTransitionIsValid(ObjectAState currentState, ObjectAState targetState)
{
  return Changes[currentState].Contains(targetState);
}

Это работает отлично - пользователи ObjectA просто передают enum текущего и целевого состояний объекта и получают простое истина или ложь для того, действителен ли переход. Итак, как сделать этот универсальный, чтобы тот же метод мог обрабатывать перечисления из других объектов?

Я пробовал это:

Dictionary<Enum, List<Enum>> Changes = new Dictionary<Enum, List<Enum>>();

Он компилируется без ошибок, но код, который добавляет записи в словарь, не работает:

Changes.Add(ObjectAState.ObjectAAvailable, new List<ObjectAState> { ObjectAState.ObjectADeleteRequested });

Error   1   The best overloaded method match for 'System.Collections.Generic.Dictionary<System.Enum,System.Collections.Generic.List<System.Enum>>.Add(System.Enum, System.Collections.Generic.List<System.Enum>)' has some invalid arguments
Error   2   Argument 2: cannot convert from 'System.Collections.Generic.List<MyApp.ObjectAState>' to 'System.Collections.Generic.List<System.Enum>'

У меня была охота, и я не вижу, что делаю неправильно. У кого-нибудь есть идеи, почему моя «универсальная» версия не компилируется?

Ответы [ 2 ]

3 голосов
/ 26 апреля 2011

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

Сложность заключается в том, что нет способа полностью обеспечить принудительное использование универсального типа Enum во время компиляции. Это, вероятно, ближайший к вам:

public class MyTestClass<T>
    where T : struct, IConvertible // Try to get as much of a static check as we can.
{
    // The .NET framework doesn't provide a compile-checked
    // way to ensure that a type is an enum, so we have to check when the type
    // is statically invoked.
    static EnumUtil()
    {
        // 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.");
    }

    Dictionary<T, List<T>> Changes = new Dictionary<T, List<T>>();
    ...
}
1 голос
/ 26 апреля 2011

Я думаю, это потому, что вы пытаетесь использовать не универсальный объект, хотя определение было общим.попробуй это.

Changes.Add(ObjectAState.ObjectAAvailable, new List<Enum> { ObjectAState.ObjectADeleteRequested });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...