У меня есть набор значений перечисления (точные коды ошибок).Код представляет собой 16-битное целое число без знака.Я ищу структуру данных, которая могла бы представлять такое перечисление.Аналогичный вопрос был задан здесь: Каков наилучший шаблон C # для реализации иерархии с перечислением? .Но эта иерархия глубже.
Примеры значений перечисления
Current = 0x2000,
Current_DeviceInputSide = 0x2100,
ShortToEarth = 0x2120,
ShortToEarthInPhase1 = 0x2121,
ShortToEarthInPhase2 = 0x2122,
ShortToEarthInPhase3 = 0x2123
Вариант использования
Когда пользователь предоставляет код, пользовательский интерфейс должен отображать эквивалентное значение кода с иерархией.
Например, если пользователь предоставляет значение 0x2121
, пользовательский интерфейс должен отображать Short to earth in phase 1 in the current at device input side
.Лучший способ представить это - использовать иерархическую запись: Current : DeviceInputSide : ShortToEarth : ShortToEarthInPhase1
.
Конкурирующие подходы
У меня есть три конкурирующих подхода для представления перечисления:
- Создать перечисление на каждом уровне иерархии.Затем используйте класс контроллера для разрешения имени.
- Сохраните значения перечисления в xml и используйте LINQ для генерации значения кода.
- Сохраните значения перечисления в xml.Во время запуска приложения.Создайте единичный экземпляр, чтобы получить значение.Экземпляр содержит словарь, заполненный значениями из xml.
Подход 1
Перечисления:
enum WarnCodes
{
None= 0x000,
Current = 0x2000
}
enum WarnCodes_Current
{
DeviceInputSide = 0x2100,
DeviceOutputSide = 0x2200
}
enum WarnCodes_Current_DeviceInputSide
{
ShortToEarth = 0x2120,
ShortCircuit = 0x2130
}
enum WarnCodes_Current_DeviceInputSide_ShortToEarth
{
InPhase1 = 0x2121,
InPhase2 = 0x2122
}
Контроллер:
public string GetMeaning(int code)
{
int bitMask = 0xF000;
int maskedCode = bitMask & code;
StringBuilder meaning = new StringBuilder();
switch (maskedCode)
{
case WarnCodes.Current:
meaning.Append("Current : ");
bitMask = 0xFF00;
maskedCode = bitMask & code;
switch (maskedCode)
{
case WarnCodes_Current.DeviceInputSide:
meaning.Append("Current : Device Input Side :");
...
break;
}
break;
...
}
}
Подход 2
XML для хранения значений перечисления выглядит следующим образом
<code><WarnCodes>
<code hex="2000" meaning="Current">
<code hex="2100" meaning="Current, Device Input side">
<code hex="2120" meaning="Short to Earth">
<code hex="2121" meaning="Short to earth in Phase L1"/>
<code hex="2122" meaning="Short to earth in Phase L2"/>
</code>
</code>
</code>
</WarnCodes>
И метод, используемый для запроса кодов:
XElement rootElement = XElement.Load(settingsFilePath);
public string GetHierarchicalMeaning(int code)
{
XElement rootElement = XElement.Load(warnCodesFilePath);
List<string> meanings = new List();
StringBuilder stringBuilder = new StringBuilder();
IEnumerable<XElement> elements;
elements = from el in rootElement.Descendants("code")
where (string)el.Attribute("hex") == code.ToString("X")
select el;
XElement element = elements.First();
while (element.Parent != null)
{
meanings.Add(element.Attribute("meaning").Value);
element = element.Parent;
}
meanings.Reverse();
foreach (string meaning in meanings)
{
stringBuilder.AppendFormat("{0} : ", meaning);
}
return stringBuilder.ToString().Trim().TrimEnd(':').Trim();
}
подход 3
XML для хранения значений перечисления такой же, как в подход 2 .Словарь заполняется с xml
на GetChildren()
.
private Dictionary<int, WarnCodeValue> warnCodesDictionary;
public void Initialize()
{
XElement rootElement = XElement.Load(settingsFilePath);
warnCodesDictionary = GetChildren(rootElement);
}
private Dictionary<int, WarnCodeValue> GetChildren(XElement element)
{
if (element.Descendants().Count() > 0)
{
Dictionary<int, WarnCodeValue> childNodeDictionary = new Dictionary();
foreach (XElement childElement in element.Elements())
{
int hex = Convert.ToInt32(childElement.Attribute("hex").Value, 16);
string meaning = childElement.Attribute("meaning").Value;
Dictionary<int, WarnCodeValue> dictionary = GetChildren(childElement);
WarnCodeValue warnCodeValue;
if (dictionary == null)
{
warnCodeValue = new WarnCodeValue() {Meaning = meaning};
}
else
{
warnCodeValue = new WarnCodeValue() {Meaning = meaning, ChildNodes = dictionary};
}
childNodeDictionary.Add(hex, warnCodeValue);
}
return childNodeDictionary;
}
return null;
}
Значения извлекаются с использованием GetHierarchicalMeaning()
:
public string GetHierarchicalMeaning(int code)
{
StringBuilder stringBuilder = new StringBuilder();
int firstLevel = code & 0xF000;
int secondLevel = code & 0xFF00;
int thirdLevel = code & 0xFFF0;
if(warnCodesDictionary.ContainsKey(firstLevel))
{
stringBuilder.AppendFormat("{0} : ", warnCodesDictionary[firstLevel].Meaning);
if (warnCodesDictionary[firstLevel].ChildNodes != null &&
warnCodesDictionary[firstLevel].ChildNodes.ContainsKey(secondLevel))
{
stringBuilder.AppendFormat("{0} : ", warnCodesDictionary[firstLevel].ChildNodes[secondLevel].Meaning);
if (warnCodesDictionary[firstLevel].ChildNodes[secondLevel].ChildNodes != null &&
warnCodesDictionary[firstLevel].ChildNodes[secondLevel].ChildNodes.ContainsKey(thirdLevel))
{
stringBuilder.AppendFormat("{0} : ",
warnCodesDictionary[firstLevel].ChildNodes[secondLevel].ChildNodes[thirdLevel].Meaning);
if (warnCodesDictionary[firstLevel].ChildNodes[secondLevel].ChildNodes[thirdLevel].ChildNodes != null &&
warnCodesDictionary[firstLevel].ChildNodes[secondLevel].ChildNodes[thirdLevel].ChildNodes.ContainsKey(code))
{
stringBuilder.AppendFormat("{0} : ",
warnCodesDictionary[firstLevel].ChildNodes[secondLevel].ChildNodes[thirdLevel].ChildNodes[code].Meaning);
}
}
}
}
}
Класс WarnCodeValue
:
class WarnCodeValue
{
public string Meaning
{ get; set; }
public Dictionary<int, WarnCodeValue> ChildNodes { get; set; }
}
Вопросы
- Какой из трех вышеуказанных подходов лучше с точки зрения производительности?
- Существуют ли другие способы представления перечисления?
- Есть ли улучшения в коде?