Перевод данных в байтовую последовательность формата "0x" C#

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

Как закодировать данные в байтовую последовательность?

Пример данных:

string: "Nissan",
float: 1.6F,
int: 2008

Выходные данные:

Model: "Nissan" => 0x4E 0x69 0x73 0x73 0x61 0x6E,
Engine: 1.6F => 0x3F 0xCC 0xCC 0xCD,
Year: 2008 => 0x07 0xD8

Необходимо это сделать именно через кодирование. То есть сейчас у меня сделано следующим образом:

private string ModelToHex()
{
    byte[] data = Encoding.Default.GetBytes(Model);
    string result = "";

    foreach (byte b in data)
    {
         result += " 0x" + b.ToString("X2");
    }

    return result.Trim();
}

private string YearToHex()
{
    var dataYear = Convert.ToString(Year, 16);
    var result = "";

    result += "0x0" + dataYear[0];
    result += " 0x" + dataYear[1] + dataYear[2];

    return result;
}

private string EngineCapacityToHex()
{
    var result = "";
    byte[] bytes = BitConverter.GetBytes(EngineCapacity);
    if (BitConverter.IsLittleEndian)
    {
        Array.Reverse(bytes);
    }

    foreach (byte b in bytes)
    {
        result += " 0x" + b.ToString("X2");
    }

    return result;
}

Использовано по факту 3 различных варианта перевода, но во всех трех вручную добавляется "0x" к значению. Необходимо, чтобы это добавлялось автоматически при кодировании, системными методами.

Задание

Сервер - https://github.com/Andalexshap/TCPServerConsole

Клиент - https://github.com/Andalexshap/TCPClientBySoket

Ответы

▲ 0Принят

Если выбросить сетевую часть задания, то она сводится к созданию модели данных и ее сериализации в байтовое представление.

Создаю модель данных.

public class Car
{
    public string Model { get; set; }
    public ushort Year { get; set; }
    public float Engine { get; set; }
}

Далее пишу вот такой простой серализатор на основе рефлексии

public class BinarySerializer
{
    public byte[] Serialize(object model)
    {
        List<byte> bytes = new();
        bytes.Add(0x02);
        PropertyInfo[] properties = model.GetType().GetProperties();
        bytes.Add((byte)properties.Length);
        foreach (var prop in properties)
        {
            switch (prop.GetValue(model)) 
            {
                case string text:
                    WriteString(text, bytes);
                    break;
                case ushort uint16:
                    WriteUInt16(uint16, bytes);
                    break;
                case float single:
                    WriteSingle(single, bytes);
                    break;
                default:
                    throw new ArgumentException("Unsupported Property Type");
            }
        }
        return bytes.ToArray();
    }

    private void WriteString(string text, List<byte> result)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(text);
        result.Add(0x09);
        result.Add((byte)bytes.Length);
        result.AddRange(bytes);
    }

    private void WriteSingle(float number, List<byte> result)
    {
        result.Add(0x13);
        byte[] buffer = new byte[sizeof(float)];
        BinaryPrimitives.WriteSingleBigEndian(buffer, number);
        result.AddRange(buffer);
    }

    private void WriteUInt16(ushort number, List<byte> result)
    {
        result.Add(0x12);
        byte[] buffer = new byte[sizeof(ushort)];
        BinaryPrimitives.WriteUInt16BigEndian(buffer, number);
        result.AddRange(buffer);
    }
}

А запустить это можно вот так

Car car = new()
{
    Model = "Nissan",
    Year = 2008,
    Engine = 1.6f
};
BinarySerializer serializer = new();
byte[] bytes = serializer.Serialize(car);

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

Можно еще его потестировать.

string hex = Convert.ToHexString(bytes);
Console.WriteLine(hex);
string prefixHex = string.Join(' ', hex.Chunk(2).Select(x => "0x" + new string(x)));
Console.WriteLine(prefixHex);
byte[] test = new byte[] { 0x02, 0x03, 09, 0x06, 0x4E, 0x69, 0x73, 0x73, 0x61, 0x6E, 0x12, 0x07, 0xD8, 0x13, 0x3F, 0xCC, 0xCC, 0xCD };
Console.WriteLine($"Test passed: {(bytes.SequenceEqual(test) ? "Success" : "FAILURE")}");

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

020309064E697373616E1207D8133FCCCCCD
0x02 0x03 0x09 0x06 0x4E 0x69 0x73 0x73 0x61 0x6E 0x12 0x07 0xD8 0x13 0x3F 0xCC 0xCC 0xCD
Test passed: Success