У меня есть структура, представляющая пакет формата провода. В этой структуре есть множество других структур. У меня есть общий код, который очень хорошо справляется с этим для большинства случаев, но этот случай массива структур бросает маршаллер для цикла.
Небезопасный код не годится, так как я не могу получить указатель на структуру с массивом (ах!).
Из эта статья проекта я вижу, что существует очень хороший общий подход с использованием C++ / CLI, который выглядит примерно так ...
public ref class Reader abstract sealed
{
public:
generic <typename T> where T : value class
static T Read(array<System::Byte>^ data)
{
T value;
pin_ptr<System::Byte> src = &data[0];
pin_ptr<T> dst = &value;
memcpy((void*)dst, (void*)src,
/*System::Runtime::InteropServices::Marshal::SizeOf(T::typeid)*/
sizeof(T));
return value;
}
};
Теперь, если бы у меня была только структура -> байтовый массив / версия писателя, я бы установил! Заранее спасибо!





Использование memcpy для копирования массива байтов в структуру чрезвычайно опасно, если вы не контролируете упаковку байтов в структуре. Безопаснее маршалировать и демаршалировать структуру по одному полю за раз. Конечно, вы потеряете общую функцию примера кода, который вы предоставили.
Чтобы ответить на ваш реальный вопрос (и рассмотрите этот псевдокод):
public ref class Writer abstract sealed
{
public:
generic <typename T> where T : value class
static System::Byte[] Write(T value)
{
System::Byte buffer[] = new System::Byte[sizeof(T)]; // this syntax is probably wrong.
pin_ptr<System::Byte> dst = &buffer[0];
pin_ptr<T> src = &value;
memcpy((void*)dst, (void*)src,
/*System::Runtime::InteropServices::Marshal::SizeOf(T::typeid)*/
sizeof(T));
return buffer;
}
};
Вероятно, это неправильный путь. CLR позволяет добавлять отступы, изменять порядок элементов и изменять способ их хранения в памяти.
Если вы хотите сделать это, не забудьте добавить атрибут [System.Runtime.InteropServices.StructLayout], чтобы задать конкретный макет памяти для структуры. В общем, предлагаю не связываться с разметкой памяти .NET-типов.
Не изменять структуру, безусловно, является разумным советом. Я использую большое количество атрибутов StructLayout для указания упаковки, макета и кодировки символов. Все течет нормально.
Моя проблема в том, что мне нужно эффективное и, желательно, общее решение. Производительность, потому что это серверное приложение, универсальное для элегантности. Если вы посмотрите ссылку codeproject, вы увидите, что методы StructureToPtr и PtrToStructure работают примерно в 20 раз медленнее, чем простое небезопасное приведение указателя. Это одна из тех областей, где небезопасный код всегда приносит пользу. C# позволит вам иметь указатели только на примитивы (и он не является универсальным - не может получить указатель на универсальный), поэтому CLI.
Спасибо за горечь псевдокода, посмотрю, выполнит ли он свою работу, и доложу.
Я что-то упускаю? Почему бы не создать новый массив того же размера и инициализировать каждый элемент отдельно в цикле?
Использование массива байтовых данных довольно опасно, если вы не нацеливаетесь только на одну платформу ... например, ваш метод не учитывает различие в порядке байтов между исходным и целевым массивами.
Что-то, что я действительно не понимаю в вашем вопросе, - это то, почему наличие массива в качестве члена в вашем классе вызывает проблему. Если класс исходит из языка .NET, у вас не должно возникнуть проблем, в противном случае вы сможете взять указатель в небезопасном коде и инициализировать новый массив, пройдя по элементам, указанным на них, один за другим (с небезопасным кодом) и добавив их к этому.
На самом деле, для этого можно создать небезопасный код. См. Мой пост о чтении структур с диска: Чтение массивов из файлов на C# без лишнего копирования.