繁体   English   中英

从字符串中解析代码符号以构建枚举数组的有效方法

[英]Efficient way to parse code symbols from a string to build enum array

我从远程设备获取数据,该设备发送带有包含单字母代码的状态字符串的数字数据。 我需要将字符串中的所有单字符状态代码映射到相应的枚举值,并将这些枚举值放入一个属性中,然后类使用者可以调用它来了解状态,而无需查找单字符状态代码。 示例状态字符串是“...QD.B”。

是否有一种模式可以在不使用巨大的 switch 语句或多个 if 语句的情况下做到这一点?

注意:该代码实际上包含了 20 多种状态,但为了简洁起见,我已将它们编辑掉。

[Flags]
public enum DataQuality
{
    Good = 0x0001,                           
    Questionable = 0x0004,                  
    NotCorrected = 0x0008,             
    BadEstimatedValue = 0x0010        
}

public class DataPointStatus
{
    private const string Good = "...";
    private const char Questionable = 'Q';
    private const char NotCorrected = 'D';
    private const char BadEstimatedValue = 'B';
    // Lot's more statuses...

    private readonly string _rawStatus;
    private readonly List<DataQuality> _statuses = new List<DataQuality>();

    public DataPointStatus(string rawStatus)
    {
        if (rawStatus == null)
        {
            throw new ArgumentNullException($"'{nameof(rawStatus)}' cannot be null.");
        }

        if (rawStatus.Trim() == string.Empty)
        {
            throw new ArgumentException($"'{nameof(rawStatus)}' cannot be an empty string.");
        }

        _rawStatus = rawStatus;

        SetStatusToGoodIfDataHasNoQualityErrors();
        if (!IsGood) SetBadQualityStatuses();
    }

    public bool IsGood => _statuses.Any(x => x == DataQuality.Good);
    public IEnumerable<DataQuality> Statuses => _statuses;

    private void CheckForGoodStatus()
    {
        if (_rawStatus == Good)
        {
            _statuses.Add(DataQuality.Good);
        }
    }

    private void SetStatusToGoodIfDataHasNoQualityErrors()
    {
        string status = _rawStatus.Replace(".", string.Empty);

        Start:
        switch (status)
        {
            case string s when s == "": return;

            case string s when s.Contains(Questionable):
                _statuses.Add(DataQuality.Questionable);
                status = status.Trim(Questionable);
                goto Start;

            case string s when s.Contains(NotCorrected):
                _statuses.Add(DataQuality.NotCorrected);
                status = status.Trim(NotCorrected);
                goto Start;

            case string s when s.Contains(BadEstimatedValue):
                _statuses.Add(DataQuality.BadEstimatedValue);
                status = status.Trim(BadEstimatedValue);
                goto Start;

            default:
                throw new ArgumentOutOfRangeException(
                    $"Invalid status code.");
        }
    }
}

您可以将枚举存储在字典中:

var dic = new Dictionary<string, DataQuality>(StringComparer.OrdinalIgnoreCase)
{
    ["G"] = DataQuality.Good,
    ["Q"] = DataQuality.Questionable,
    ["N"] = DataQuality.NotCorrected,
    ["B"] = DataQuality.BadEstimatedValue
};
string input = "Q";
if (dic.TryGetValue(input, out var status))
{
    // Use "status" variable here
}

您可以使用正则表达式来查找状态

//Regular expression can be more elaborated, 
//searching the status char in a concrete part of the string and so on
Regex regex = new Regex("Q|D|B"); 

然后是一个字典来匹配字符串值与相应的标志值

Dictionary<string, DataQuality> qualities = InitializeDictionary();

这应该放在一个循环中。 类似于while (rawStatus != "")

Match match = regex.Match(rawStatus);
if (match.Success) {
    _statuses.Add(qualities[match.Value]);
    rawStatus = regex.Replace(rawStatus, "");
}

这不会直接适用于您的代码,因为您需要 Flag。
要将字符串解析为枚举值列表,您可以使用 char Enum :

Enum MyEnum
{
    Good = 'g',
    Questionable = 'q',
    NotCorrected = 'n',
    BadEstimatedValue = 'b'
    //[...]
}

您可以使用Enum.TryParseParse将字符串转换为他的枚举值。
但是对于一个字符,一个简单的转换(MyEnum)myChar就足够了。
这会将所有 char 转换为 int 值,即使它们未在枚举中定义。
Enum.IsDefined将指示它是否存在于指定的枚举中。

对于字符枚举:

var input = "qngb###qnga";
var result = input.Where(x => Enum.IsDefined(typeof(toto), (int)x))
                  .Select(x => (toto)x);

结果:

可疑的
未更正
好的
错误估计值
可疑的
未更正
好的

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM