表示层次枚举

发布于 2024-10-17 22:43:35 字数 6637 浏览 3 评论 0原文

我有一组枚举值(准确地说是故障代码)。该代码是一个 16 位无符号整数。我正在寻找一种可以表示此类枚举的数据结构。这里提出了类似的问题: 使用枚举实现层次结构的最佳 C# 模式是什么?。但这个层次结构更深。


示例枚举值

Current = 0x2000,
Current_DeviceInputSide = 0x2100,
ShortToEarth = 0x2120,
ShortToEarthInPhase1 = 0x2121,
ShortToEarthInPhase2 = 0x2122,
ShortToEarthInPhase3 = 0x2123


用例
当用户提供代码时,UI 必须显示该代码与层次结构的等效含义。
例如,如果用户提供值 0x2121,则 UI 必须显示设备输入侧电流第 1 阶段对地短路。表示这一点的最佳方法是使用分层表示法:Current : DeviceInputSide : ShortToEarth : ShortToEarthInPhase1


竞争方法
我有三种相互竞争的方法来表示枚举:

  1. 在层次结构的每个级别创建一个枚举。然后使用控制器类来解析名称。
  2. 将枚举值存储在 xml 中并使用 LINQ 生成代码的含义。
  3. 将枚举值存储在 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 如下所示

<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>
And the method used to query the codes is:

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 中的相同。该字典由 GetChildren()xml 填充。

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


问题

  1. 从性能角度来看,上述 3 种方法中哪一种更好?
  2. 还有其他方法来表示枚举吗?
  3. 代码有什么改进吗?

I have a set of enumeration values (fault codes to be precise). The code is a 16 bit unsigned integer. I am looking for a data structure that could represent such an enumeration. A similar question has been asked here: What's the best C# pattern for implementing a hierarchy with an enum?. But this hierarchy is deeper.

Sample enumeration values

Current = 0x2000,
Current_DeviceInputSide = 0x2100,
ShortToEarth = 0x2120,
ShortToEarthInPhase1 = 0x2121,
ShortToEarthInPhase2 = 0x2122,
ShortToEarthInPhase3 = 0x2123

Use case
When the user provides a code then the UI has to display the equivalent meaning of the code with the hierarchy.

For example, if the user provides a value 0x2121 then the UI has to display Short to earth in phase 1 in the current at device input side. The best way to represent this is by using a hierarchical notation: Current : DeviceInputSide : ShortToEarth : ShortToEarthInPhase1.

Competing approaches
I have three competing approaches to represent the enumeration:

  1. Create an enumeration at each level of the hierarchy. Then use a controller class to resolve the name.
  2. Store the enumeration values in an xml and use LINQ to generate the meaning of the code.
  3. Store the enumeration values in an xml. During the application startup. Create a singleton instance to retrieve the meaning. The instance contains a dictionary populated with the values from the xml.

Approach 1
The enumerations:

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
}

The controller:

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;

            ...
    }
}

Approach 2
The xml to store the enumeration values looks like this

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


And the method used to query the codes is:

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

Approach 3
The xml to store the enumeration values is same as in Approach 2. The dictionary is populated from the xml by 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;
}

The meanings are retrieved using 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);
                }
            }
        }
    }
}

The WarnCodeValue class:

class WarnCodeValue
{
    public string Meaning
    { get; set; }

    public Dictionary<int, WarnCodeValue> ChildNodes { get; set; }
}

Questions

  1. Which of the above 3 approaches is better from a performance point of view?
  2. Are there any other approaches for representing the enumeration?
  3. Any improvements to the code?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

太傻旳人生 2024-10-24 22:43:35

考虑使用类而不是枚举,然后为每个值使用单例,并可以使用类型系统构建树,包括生成错误txt等的虚拟方法。(这有时可以是一个不错的选择,但如果不合适也会导致你很多问题

Consider using classes instead of enums, you then use a singleton for each value and can use the type system to build a tree, including virtual methods to produce error txt etc. (This can sometimes be a good option, but can also lead you into lots of problems if it does not fit well)

遇见了你 2024-10-24 22:43:35

您可以使用 FlagsAttribute
例如你可以这样做:

[FlagsAttribute]
enum WarnCodes
{
    None= 0x0000,
    Current = 0x2000,

    // second level of hierarchy
    DeviceInputSide = 0x0100,
    DeviceOutputSide = 0x0200,

    // third level of hierarchy
    ShortToEarth = 0x0020,
    ShortCircuit = 0x0030,

    // fourth level of hierarchy
    InPhase1 = 0x0001,
    InPhase2 = 0x0002
}       

你可以这样测试它:

int[] testVals = {0x0000, 0x2000, 0x2130, 0x2122, 0x2121, 0x2131};

foreach(var val in testVals)
{
   Console.WriteLine( "{0,4:X} - {1}",
      val, ( (WarnCodes)val ).ToString( ) );
}

You could use FlagsAttribute.
For instance you could do something like this:

[FlagsAttribute]
enum WarnCodes
{
    None= 0x0000,
    Current = 0x2000,

    // second level of hierarchy
    DeviceInputSide = 0x0100,
    DeviceOutputSide = 0x0200,

    // third level of hierarchy
    ShortToEarth = 0x0020,
    ShortCircuit = 0x0030,

    // fourth level of hierarchy
    InPhase1 = 0x0001,
    InPhase2 = 0x0002
}       

You can test it like this:

int[] testVals = {0x0000, 0x2000, 0x2130, 0x2122, 0x2121, 0x2131};

foreach(var val in testVals)
{
   Console.WriteLine( "{0,4:X} - {1}",
      val, ( (WarnCodes)val ).ToString( ) );
}
顾铮苏瑾 2024-10-24 22:43:35

第二次尝试...您可以实现自己的树结构,其中每个节点都有一位十六进制表示形式,并且像 0x2121 这样的代码表示树的分支:

                      >2 - (current)
                      / \
 (device input side)>1   2 (device output side)
                    /\   /\
                     >2 (short to earth)
                     /\  
                   >1 (in phase 1) 

因此,要读取 0x2121 的含义,我们遵循树的相应分支并且(对于每个节点)我们读取它包含的消息。

这是树的快速而肮脏的实现:

public class TreeNode
{
    private List<TreeNode> _children;

    public int hex {get; private set;}
    public string meaning {get; private set;}
    public IList<TreeNode> children {
        get{
            return _children.AsReadOnly();
        }
    }

    public TreeNode(int hex, string meaning)
    {
        this.hex = hex;
        this.meaning = meaning;
        _children = new List<TreeNode>();
    }

    public TreeNode addChild(int hex, string meaning)
    {
        if(hex<=0 || hex >=16) throw new ArgumentOutOfRangeException("hex");
        if(GetChildByCode(hex)!=null) throw new Exception("a child with code " + 
                                             hex.ToString() + " already exists");                   
        var child = new TreeNode(hex,meaning);
         _children.Add(child);
        return child;
    }

    public TreeNode TryAddChild(int hex, string meaning)
    {
        if(hex<=0 || hex >=16) throw new ArgumentOutOfRangeException("hex");
        var chd = GetChildByCode(hex);

        if(chd==null) { 
            chd = new TreeNode(hex,meaning);
            _children.Add(chd);
        }
        return chd;         
    }

    public void AddBranch(int hexPath, string[] meanings)
    {
        var lst = intToList(hexPath,16,new LinkedList<int>()).ToList();        
        var curNode = this;
        for(int i = 0; i<lst.Count; i++)
        {
            curNode = curNode.TryAddChild(lst[i], meanings[i]);             
        }                         
    }

    public TreeNode GetChildByCode(int hex)
    {
        return 
            (from c in _children
            where c.hex == hex
            select c).SingleOrDefault();          
    }

    public string getMessagesByPath(int hexPath)
    {            
        var lst = intToList(hexPath,16,new LinkedList<int>());
        var msgs = getMessagesByPath(lst, new List<string>(),this);
        return
            (msgs == null || msgs.Count==0) ?
                "None":
                msgs.Aggregate((s1, s2) => s1 + ": " + s2);
    }


    // recursively follow the branch and read the node messages
    protected IList<string> getMessagesByPath(LinkedList<int> hexPath, IList<string> accString, TreeNode curNode) 
    {
        if(hexPath.Count == 0 || hexPath.First.Value == 0 || curNode==null) 
            return accString;
        else   
        {
            var chd = curNode.GetChildByCode(hexPath.First.Value);                
            string meaning = (chd==null)? "not found": chd.meaning;
            accString.Add(meaning);
            hexPath.RemoveFirst();
            return getMessagesByPath(hexPath,accString,chd);
        }
    }

    // convert the code to a list of digits in the given base (in this case 16)
    // this could be an extension method for int      
    private LinkedList<int> intToList(int theInt, int theBase, LinkedList<int> acc)
    {
        if(theInt < theBase) 
        {
            acc.AddFirst(theInt);
            return acc;
        }
        else
        {
            acc.AddFirst(theInt % theBase);
            return intToList(theInt/theBase, theBase, acc);
        }
    }
}

您可以通过这种方式填充树:

        var root = new TreeNode(0,"root");        

        root.AddBranch(0x2121, new string[] {"Current", "DeviceInputSide", "Short to Earth", "In phase I"});
        root.AddBranch(0x2122, new string[] {"Current", "DeviceInputSide", "Short to Earth", "In phase II"});
        root.AddBranch(0x2123, new string[] {"Current", "DeviceInputSide", "Short to Earth", "In phase III"});
        root.AddBranch(0x2221, new string[] {"Current", "DeviceOutputSide", "Short to Earth", "In phase I"});
        root.AddBranch(0x2222, new string[] {"Current", "DeviceOutputSide", "Short to Earth", "In phase II"});
        root.AddBranch(0x2223, new string[] {"Current", "DeviceOutputSide", "Short to Earth", "In phase III"});
// ...

这样您就可以完全控制代码的层次结构,并可以实现检查,以便结构本身不会被损坏。搜索消息仍然很容易(因为它不处理第一个 0 之后的代码),搜索 0x2000 应该更有效,因为实际上只处理了 2。

//search meaning of path
root.getMessagesByPath(0x2122)

Second attempt... You could implement your own tree structure where each node has a single-digit hexadecimal representation and a code like 0x2121 represents a branch of the tree:

                      >2 - (current)
                      / \
 (device input side)>1   2 (device output side)
                    /\   /\
                     >2 (short to earth)
                     /\  
                   >1 (in phase 1) 

So, to read what 0x2121 means, we follow the corresponding branch of the tree and (for each node) we read the message it contains.

Here's a quick and dirty implementation of the tree:

public class TreeNode
{
    private List<TreeNode> _children;

    public int hex {get; private set;}
    public string meaning {get; private set;}
    public IList<TreeNode> children {
        get{
            return _children.AsReadOnly();
        }
    }

    public TreeNode(int hex, string meaning)
    {
        this.hex = hex;
        this.meaning = meaning;
        _children = new List<TreeNode>();
    }

    public TreeNode addChild(int hex, string meaning)
    {
        if(hex<=0 || hex >=16) throw new ArgumentOutOfRangeException("hex");
        if(GetChildByCode(hex)!=null) throw new Exception("a child with code " + 
                                             hex.ToString() + " already exists");                   
        var child = new TreeNode(hex,meaning);
         _children.Add(child);
        return child;
    }

    public TreeNode TryAddChild(int hex, string meaning)
    {
        if(hex<=0 || hex >=16) throw new ArgumentOutOfRangeException("hex");
        var chd = GetChildByCode(hex);

        if(chd==null) { 
            chd = new TreeNode(hex,meaning);
            _children.Add(chd);
        }
        return chd;         
    }

    public void AddBranch(int hexPath, string[] meanings)
    {
        var lst = intToList(hexPath,16,new LinkedList<int>()).ToList();        
        var curNode = this;
        for(int i = 0; i<lst.Count; i++)
        {
            curNode = curNode.TryAddChild(lst[i], meanings[i]);             
        }                         
    }

    public TreeNode GetChildByCode(int hex)
    {
        return 
            (from c in _children
            where c.hex == hex
            select c).SingleOrDefault();          
    }

    public string getMessagesByPath(int hexPath)
    {            
        var lst = intToList(hexPath,16,new LinkedList<int>());
        var msgs = getMessagesByPath(lst, new List<string>(),this);
        return
            (msgs == null || msgs.Count==0) ?
                "None":
                msgs.Aggregate((s1, s2) => s1 + ": " + s2);
    }


    // recursively follow the branch and read the node messages
    protected IList<string> getMessagesByPath(LinkedList<int> hexPath, IList<string> accString, TreeNode curNode) 
    {
        if(hexPath.Count == 0 || hexPath.First.Value == 0 || curNode==null) 
            return accString;
        else   
        {
            var chd = curNode.GetChildByCode(hexPath.First.Value);                
            string meaning = (chd==null)? "not found": chd.meaning;
            accString.Add(meaning);
            hexPath.RemoveFirst();
            return getMessagesByPath(hexPath,accString,chd);
        }
    }

    // convert the code to a list of digits in the given base (in this case 16)
    // this could be an extension method for int      
    private LinkedList<int> intToList(int theInt, int theBase, LinkedList<int> acc)
    {
        if(theInt < theBase) 
        {
            acc.AddFirst(theInt);
            return acc;
        }
        else
        {
            acc.AddFirst(theInt % theBase);
            return intToList(theInt/theBase, theBase, acc);
        }
    }
}

you can populate the tree this way:

        var root = new TreeNode(0,"root");        

        root.AddBranch(0x2121, new string[] {"Current", "DeviceInputSide", "Short to Earth", "In phase I"});
        root.AddBranch(0x2122, new string[] {"Current", "DeviceInputSide", "Short to Earth", "In phase II"});
        root.AddBranch(0x2123, new string[] {"Current", "DeviceInputSide", "Short to Earth", "In phase III"});
        root.AddBranch(0x2221, new string[] {"Current", "DeviceOutputSide", "Short to Earth", "In phase I"});
        root.AddBranch(0x2222, new string[] {"Current", "DeviceOutputSide", "Short to Earth", "In phase II"});
        root.AddBranch(0x2223, new string[] {"Current", "DeviceOutputSide", "Short to Earth", "In phase III"});
// ...

this way you get total control over the hierarchical structure of your codes and can implement checks so that the structure itself cannot be corrupted. Searching a message remains easy and (since it does not process a code after the first 0), a search for 0x2000 should be more efficient because only the 2 is actually processed.

//search meaning of path
root.getMessagesByPath(0x2122)
仙女 2024-10-24 22:43:35

发现方法3的修改版本最合适。感谢@paolo帮助我找到答案。

修改方法 3

包含代码的 xml

<?xml version="1.0" encoding="utf-8" ?>
<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>
  <code hex="3000" meaning="Voltage"/>
</WarnCodes>

WarnCodeValue 类:

class WarnCodeValue
{
    public string Meaning
    { get; set; }

    public string ConcatenatedMeaning
    { get; set; }

    public Dictionary<int, WarnCodeValue> ChildNodes 
    { get; set; }
}

singleton 处理器类(用于检索代码的含义):

sealed class WarnCodeProcessor
{
    private static Dictionary<int, WarnCodeValue> warnCodesDictionary;

    private static volatile WarnCodeProcessor _instance;

    private static object instanceLockCheck = new object();

    public static WarnCodeProcessor Instance
    {
        get
        {
            lock (instanceLockCheck)
            {
                if (_instance == null)
                {
                    _instance = new WarnCodeProcessor();
                }
            }

            return _instance;
        }
    }

    private WarnCodeProcessor()
    {
        warnCodesDictionary = new Dictionary<int, WarnCodeValue>();

        string currentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        string settingsFilePath = Path.Combine(currentDirectory, "WarnCodes.xml");
        XElement rootElement = XElement.Load(settingsFilePath);

        warnCodesDictionary = GetChildren(rootElement, string.Empty);
    }

    public string GetConcatenatedMeaning(int code)
    {
        string concatenatedMeaning = string.Empty;

        int firstLevel = code & 0xF000;
        int secondLevel = code & 0xFF00;
        int thirdLevel = code & 0xFFF0;

        if (warnCodesDictionary.ContainsKey(firstLevel))
        {
            concatenatedMeaning = warnCodesDictionary[firstLevel].ConcatenatedMeaning;

            if (warnCodesDictionary[firstLevel].ChildNodes != null &&
                warnCodesDictionary[firstLevel].ChildNodes.ContainsKey(secondLevel))
            {
                concatenatedMeaning = 
                    warnCodesDictionary[firstLevel].
                    ChildNodes[secondLevel].ConcatenatedMeaning;

                if (warnCodesDictionary[firstLevel].ChildNodes[secondLevel].ChildNodes != null &&
                    warnCodesDictionary[firstLevel].ChildNodes[secondLevel].ChildNodes.ContainsKey(thirdLevel))
                {
                    concatenatedMeaning = 
                        warnCodesDictionary[firstLevel].
                        ChildNodes[secondLevel].
                        ChildNodes[thirdLevel].ConcatenatedMeaning;

                    if (warnCodesDictionary[firstLevel].ChildNodes[secondLevel].ChildNodes[thirdLevel].ChildNodes != null &&
                        warnCodesDictionary[firstLevel].ChildNodes[secondLevel].ChildNodes[thirdLevel].ChildNodes.ContainsKey(code))
                    {
                        concatenatedMeaning = 
                            warnCodesDictionary[firstLevel].
                            ChildNodes[secondLevel].
                            ChildNodes[thirdLevel].
                            ChildNodes[code].ConcatenatedMeaning;
                    }
                }
            }
        }

        return concatenatedMeaning;
    }

    private static Dictionary<int, WarnCodeValue> GetChildren(XElement element, string concatenatedMeaning)
    {
        string elementMeaning = string.Empty;
        XAttribute attribute = element.Attribute("meaning");
        if (attribute != null)
        {
            elementMeaning = attribute.Value;
            concatenatedMeaning =
                string.IsNullOrEmpty(concatenatedMeaning) ? elementMeaning : string.Format("{0} : {1}", concatenatedMeaning, elementMeaning);
        }

        if (element.Descendants().Count() > 0)
        {
            Dictionary<int, WarnCodeValue> childNodeDictionary = new Dictionary<int, WarnCodeValue>();

            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, concatenatedMeaning);

                WarnCodeValue warnCodeValue = new WarnCodeValue();
                warnCodeValue.ChildNodes = dictionary;
                warnCodeValue.Meaning = meaning;
                warnCodeValue.ConcatenatedMeaning =
                    string.IsNullOrEmpty(concatenatedMeaning) ? meaning : string.Format("{0} : {1}", concatenatedMeaning, meaning);

                childNodeDictionary.Add(hex, warnCodeValue);
            }

            return childNodeDictionary;
        }

        return null;
    }
}

用法

string concatenatedMeaning = WarnCodeProcessor.Instance.GetConcatenatedMeaning(0x2121);

输出
电流:电流,设备输入侧:对地短路:L1 相对地短路

可能的修改包括使用GetMeaning(code)来检索代码的原始含义,而不是串联的含义。

Found that a modified version of Approach 3 is most suitable. Thanks to @paolo for helping me come up with the answer.

Modified Approach 3

The xml containing the codes:

<?xml version="1.0" encoding="utf-8" ?>
<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>
  <code hex="3000" meaning="Voltage"/>
</WarnCodes>

The WarnCodeValue class:

class WarnCodeValue
{
    public string Meaning
    { get; set; }

    public string ConcatenatedMeaning
    { get; set; }

    public Dictionary<int, WarnCodeValue> ChildNodes 
    { get; set; }
}

The singleton processor class (to retrieve the meaning of a code):

sealed class WarnCodeProcessor
{
    private static Dictionary<int, WarnCodeValue> warnCodesDictionary;

    private static volatile WarnCodeProcessor _instance;

    private static object instanceLockCheck = new object();

    public static WarnCodeProcessor Instance
    {
        get
        {
            lock (instanceLockCheck)
            {
                if (_instance == null)
                {
                    _instance = new WarnCodeProcessor();
                }
            }

            return _instance;
        }
    }

    private WarnCodeProcessor()
    {
        warnCodesDictionary = new Dictionary<int, WarnCodeValue>();

        string currentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        string settingsFilePath = Path.Combine(currentDirectory, "WarnCodes.xml");
        XElement rootElement = XElement.Load(settingsFilePath);

        warnCodesDictionary = GetChildren(rootElement, string.Empty);
    }

    public string GetConcatenatedMeaning(int code)
    {
        string concatenatedMeaning = string.Empty;

        int firstLevel = code & 0xF000;
        int secondLevel = code & 0xFF00;
        int thirdLevel = code & 0xFFF0;

        if (warnCodesDictionary.ContainsKey(firstLevel))
        {
            concatenatedMeaning = warnCodesDictionary[firstLevel].ConcatenatedMeaning;

            if (warnCodesDictionary[firstLevel].ChildNodes != null &&
                warnCodesDictionary[firstLevel].ChildNodes.ContainsKey(secondLevel))
            {
                concatenatedMeaning = 
                    warnCodesDictionary[firstLevel].
                    ChildNodes[secondLevel].ConcatenatedMeaning;

                if (warnCodesDictionary[firstLevel].ChildNodes[secondLevel].ChildNodes != null &&
                    warnCodesDictionary[firstLevel].ChildNodes[secondLevel].ChildNodes.ContainsKey(thirdLevel))
                {
                    concatenatedMeaning = 
                        warnCodesDictionary[firstLevel].
                        ChildNodes[secondLevel].
                        ChildNodes[thirdLevel].ConcatenatedMeaning;

                    if (warnCodesDictionary[firstLevel].ChildNodes[secondLevel].ChildNodes[thirdLevel].ChildNodes != null &&
                        warnCodesDictionary[firstLevel].ChildNodes[secondLevel].ChildNodes[thirdLevel].ChildNodes.ContainsKey(code))
                    {
                        concatenatedMeaning = 
                            warnCodesDictionary[firstLevel].
                            ChildNodes[secondLevel].
                            ChildNodes[thirdLevel].
                            ChildNodes[code].ConcatenatedMeaning;
                    }
                }
            }
        }

        return concatenatedMeaning;
    }

    private static Dictionary<int, WarnCodeValue> GetChildren(XElement element, string concatenatedMeaning)
    {
        string elementMeaning = string.Empty;
        XAttribute attribute = element.Attribute("meaning");
        if (attribute != null)
        {
            elementMeaning = attribute.Value;
            concatenatedMeaning =
                string.IsNullOrEmpty(concatenatedMeaning) ? elementMeaning : string.Format("{0} : {1}", concatenatedMeaning, elementMeaning);
        }

        if (element.Descendants().Count() > 0)
        {
            Dictionary<int, WarnCodeValue> childNodeDictionary = new Dictionary<int, WarnCodeValue>();

            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, concatenatedMeaning);

                WarnCodeValue warnCodeValue = new WarnCodeValue();
                warnCodeValue.ChildNodes = dictionary;
                warnCodeValue.Meaning = meaning;
                warnCodeValue.ConcatenatedMeaning =
                    string.IsNullOrEmpty(concatenatedMeaning) ? meaning : string.Format("{0} : {1}", concatenatedMeaning, meaning);

                childNodeDictionary.Add(hex, warnCodeValue);
            }

            return childNodeDictionary;
        }

        return null;
    }
}

Usage

string concatenatedMeaning = WarnCodeProcessor.Instance.GetConcatenatedMeaning(0x2121);

Output
Current : Current, Device Input side : Short to Earth : Short to earth in Phase L1

Possible modifications include a GetMeaning(code) to retrieve the original meaning of the code, rather than the concatenated meaning.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文