Добавление параметра к свойству

Рейтинг: 1Ответов: 1Опубликовано: 17.06.2023

Суть вопроса в том, что я получаю набор шестнадцатеричных данных в формате string. пример:

string dataLine = "63EDF9AC00028702F60303040800000203096000210102805000010012650309000";

Данных много, dataLine представлена не полностью.

Для начала, я перевожу dataLine в List, группируя по 2 символа:

var data = new List<string>();
    for (int i = 2; i < dataLine.Length / 2; i += 2)
    {
        data.Add(dataLine.Substring(0, 2));

        dataLine = dataLine.Substring(2);
    }

Мне нужно эти данные привести к свойствам модели. Но каждое свойство имеет разную длину в байтах. Например первые 3 из них:

    /// <summary>
    /// UNIX-штамп обновления пакета в секундах (с первого января 1970г.)
    /// Тип: 8 Целое число, беззнаковое, 4 байта
    /// Позиция: 0
    /// Количество символов: 8 
    /// </summary>
    public int PackTime { get; set; }

    /// <summary>
    /// Номер пакета (0 - данные телеметрии)
    /// Тип: Целое число, беззнаковое, 1 байт
    /// Позиция: 8
    /// Количество символов: 2 
    /// </summary>
    public int PackNo { get; set; }

    /// <summary>
    /// Позиция: 10
    /// Количество символов: 4 
    /// </summary>
    public int SW { get; set; }

Есть мысль получать все свойства модели через:

var properties = this.GetType().GetProperties();

И в цикле перебирая свойства присваивать им значения, на основании количества символов. и каждый раз удалять элементы из data,опять же согласно (количества символов)/2.

Можно ли как то добавить что то типа параметра к свойству?

Использовал вариант с кастомным атрибутом, но я не знаю на сколько это костыльно:

internal class SymbolCountAttribute : Attribute
{
    private int SymbolCount;
    public SymbolCountAttribute(int symbolCount)
    {
        SymbolCount = symbolCount;
    }
}

    /// <summary>
    /// UNIX-штамп обновления пакета в секундах (с первого января 1970г.)
    /// Тип: 8 Целое число, беззнаковое, 4 байта
    /// Позиция: 0
    /// Количество символов: 8 
    /// </summary>
    [SymbolCount(8)]
    public int PackTime { get; set; }

Данные по атрибуту получаю следующим образом:

foreach (var prop in properties)
    {
         var value = prop.CustomAttributes.First().ConstructorArguments.First().Value;
    }

Ответы

▲ 3Принят

Я вам уже давал ответ на вопрос про сериализацию.

Не надо никаких аттрибутов, надо сделать модель с типами, которые соответствуют данным, вот например так.

class MyModel
{
    /// <summary>
    /// UNIX-штамп обновления пакета в секундах (с первого января 1970г.)
    /// Тип: 8 Целое число, беззнаковое, 4 байта
    /// Позиция: 0
    /// Количество символов: 8 
    /// </summary>
    public uint PackTime { get; set; }

    /// <summary>
    /// Номер пакета (0 - данные телеметрии)
    /// Тип: Целое число, беззнаковое, 1 байт
    /// Позиция: 8
    /// Количество символов: 2 
    /// </summary>
    public byte PackNo { get; set; }

    /// <summary>
    /// Позиция: 10
    /// Количество символов: 4 
    /// </summary>
    public ushort SW { get; set; }
}

Не надо выдумывать своих преобразователей 16-ричной записи, они уже есть встроенные в .NET. Возьму к примеру только данные из начала строки, соответствующие суммарной длине ваших свойств.

string dataLine = "63EDF9AC000287";
Span<byte> data = Convert.FromHexString(dataLine);

И далее просто распарсить например используя рефлексию.

int index = 0;
MyModel model = new MyModel();
foreach (PropertyInfo prop in typeof(MyModel).GetProperties())
{ 
    switch (prop.GetValue(model))
    {
        case uint:
            prop.SetValue(model, BinaryPrimitives.ReadUInt32BigEndian(data[index..]));
            index += sizeof(uint); // 4
            break;
        case byte:
            prop.SetValue(model, data[index]);
            index++;
            break;
        case ushort:
            prop.SetValue(model, BinaryPrimitives.ReadUInt16BigEndian(data[index..]));
            index += sizeof(ushort); // 2
            break;
    }
}

Console.WriteLine(JsonSerializer.Serialize(model));
Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds(model.PackTime));

Вывод в консоль

{"PackTime":1676540332,"PackNo":0,"SW":647}
16.02.2023 09:38:52 +00:00