Я создал свои собственные псевдо-перечисления в моей модели домена, чтобы позволить мне иметь несколько более подробных значений. Например, мой класс выглядит следующим образом:
public abstract class Enumeration<X, Y> : IComparable where X : IComparable
{
public Enumeration(X value, Y displayName) { }
public Y DisplayName { get { return _displayName; } }
public X Value { get { return _value; } }
}
И класс, который наследует его, будет:
public class JobType : Enumeration<string, string>
{
public static JobType ChangeOver = new JobType("XY01", "Changeover");
public static JobType Withdrawal = new JobType("XY02", "Withdrawal");
public static JobType Installation = new JobType("XY03", "Installation");
private JobType(string jobTypeId, string description)
: base(jobTypeId, description) { }
}
Проблема заключается в том, что я хочу иметь возможность разрешать эти значения из значения, возвращаемого из базы данных в моем репозитории. Поэтому я получаю такой метод, как:
public static JobType Resolve(string jobTypeId) { return matchingJobType; }
Я начал писать метод разрешения для каждого класса перечисления, но должен быть лучший способ, чем дублирование того же метода с оператором switch в каждом?
Я думал о добавлении свойства Dictionary<X, Enumeration<X, Y>> Cache;
в базовый класс и добавлении в него класса из конструктора базового класса. Это также обеспечило бы уникальные ценности. Проблема с этим заключается в том, что когда я получаю перечисление из Словаря, это тип Enumeration<X, Y>
, и я хочу его как JobType
.
Таким образом, это означает, что нужно либо добавить третий общий тип в класс Enumeration, либо иметь:
public static T Resolve(X value); // With the additional type
public static T Resolve<T>(X value); // Or without an additional type
Мне явно не нравится идея писать JobType.Resolve<JobType>(foo);
, и я хочу просто JobType.Resolve(foo);
, но это должно быть сделано с минимальным количеством кода. То есть может ли это просто быть обработано из базового класса без необходимости включать дополнительный общий тип?
Это выглядит как ситуация для любопытно повторяющегося шаблона шаблона. Если вы хотите, чтобы метод базового типа возвращал производный класс без литья, вы можете передать производный тип в базовый тип, ограничивая производный тип, который должен быть получен из базового типа, например.
public abstract class Enumeration<TEnum, X, Y> : IComparable
where TEnum : Enumeration<TEnum, X, Y>
where X : IComparable
{
public static TEnum Resolve(X value) { /* your lookup here */ }
// other members same as before; elided for clarity
}
Затем вы определяете свои конкретные классы следующим образом.
public class JobType : Enumeration<JobType, string, string>
{
// other members same as before; elided for clarity
}
Теперь ваши типы будут совпадать и не будут выполняться кастинг для метода базового класса Resolve
.
JobType type = JobType.Resolve("XY01");
Как вы сохраняете значение для сопоставления экземпляров в базовом классе, зависит от вас. Похоже, вы уже знаете, как это сделать в любом случае, и вам просто нужно немного помочь, чтобы типы соответствовали друг другу.
Ваш реальный класс перечисления может быть более сложным, чем это, но ваша текущая реализация выглядит так, что ее можно было бы определить гораздо проще, как стандартное перечисление в сочетании с шаблоном DAL или просто словарь:
public enum JobType
{
ChangeOver,
Withdrawal,
Installation,
}
// Maybe inside some DAL-pattern/database parsing class:
var databaseToJobTypeMap = new Dictionary<string, JobType>()
{
{ "XY01", JobType.ChangeOver },
// ...
};
Сохранение кода анализа вместе (возможно, с абстракцией интерфейса) дает вам возможность переключать парсеры при изменении/изменении формата хранения данных или при наличии нескольких источников данных.
Если вам нужно проанализировать фактические значения JobType (например, строку "ChangeOver" или целочисленное представление), вы можете использовать Enum.Parse/Enum.TryParse или casting.
Реализация, которая у вас есть, выглядит более негибкой, поскольку она блокирует тип перечисления одним стилем/представлением отображения словаря.