Перевод данных в байтовую последовательность формата "0x" C#
Как закодировать данные в байтовую последовательность?
Пример данных:
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
Ответы (1 шт):
Если выбросить сетевую часть задания, то она сводится к созданию модели данных и ее сериализации в байтовое представление.
Создаю модель данных.
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
