байтовый массив из указанного c индекса как структура в c# без создания копии - PullRequest
1 голос
/ 11 июля 2020

В настоящее время я кодирую мусор клиент-сервер и много работаю со структурами C ++, передаваемыми по сети. Я знаю способы, представленные здесь Чтение структуры данных C / C ++ в C# из байтового массива , но все они о создании копии.

Я хочу иметь что-то вроде этого:

struct/*or class*/ SomeStruct
{
    public uint F1;
    public uint F2;
    public uint F3;
}

Позже в моем коде я хочу иметь что-то вроде этого:

byte[] Data; //16 bytes that I got from network
SomeStruct PartOfDataAsSomeStruct { get { return /*make SomeStruct instance based on this.Data starting from index 4, without copying it. So when I do PartOfDataAsSomeStruct.F1 = 132465; it also changes bytes 4, 5, 6 and 7 in this.Data.*/; } }

Если это возможно, расскажите, пожалуйста, как?

Ответы [ 2 ]

3 голосов
/ 11 июля 2020

Вот так?

byte[] data = new byte[16];
// 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
Console.WriteLine(BitConverter.ToString(data));
ref SomeStruct typed = ref Unsafe.As<byte, SomeStruct>(ref data[4]);
typed.F1 = 42;
typed.F2 = 3;
typed.F3 = 9;
// 00-00-00-00-2A-00-00-00-03-00-00-00-09-00-00-00
Console.WriteLine(BitConverter.ToString(data));

Приводит данные из середины массива байтов, используя ref-local, который является «внутренним управляемым указателем» на данные. Нулевые копии.

Если вам нужно несколько элементов (например, как будет работать вектор), вы можете сделать то же самое с промежутками и MemoryMarshal.Cast

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

Для промежутков:

byte[] data = new byte[256];
// create a span of some of it
var span = new Span<byte>(data, 4, 128);
// now coerce the span
var typed = MemoryMarshal.Cast<byte, SomeStruct>(span);
Console.WriteLine(typed.Length); // 10 of them fit
typed[3].F1 = 3; // etc
0 голосов
/ 11 июля 2020

Спасибо за исправление, мар c Gravell. И спасибо за пример.

Вот способ использования классовых и побитовых операторов без указателей для того же:

    class SomeClass
    {
        public byte[] Data;

        public SomeClass()
        {
            Data = new byte[16];
        }

            public uint F1
        {
            get
            {
                uint ret = (uint)(Data[4] << 24 | Data[5] << 16 | Data[6] << 8 | Data[7]);
                return ret;
            }
            set
            {
                Data[4] = (byte)(value >> 24);
                Data[5] = (byte)(value >> 16);
                Data[6] = (byte)(value >> 8);
                Data[7] = (byte)value;
            }
        }        
    }

Тестирование:

            SomeClass sc = new SomeClass();
            sc.F1 = 0b_00000001_00000010_00000011_00000100;
            Console.WriteLine(sc.Data[3].ToString() + " " + sc.Data[4].ToString() + " " + sc.Data[5].ToString() + " " + sc.Data[6].ToString());
            Console.WriteLine(sc.F1.ToString());
//Output:
//1 2 3 4
//16909060
...