Если вы хотите создать управляемый интерфейс для собственной библиотеки DLL, вам придется маршалировать данные туда-сюда. Там действительно нет способа избежать этой проблемы.
В настоящее время мы сталкиваемся с аналогичной проблемой в одном из наших текущих проектов. Подход, который мы выбрали, состоит в том, чтобы использовать PInvoke для разговора Managed -> Native. За некоторыми исключениями, мы используем только BlIntable типы PInvoke, что помогает снизить стоимость маршалинга, поскольку CLR может просто реализовать его как копию памяти.
При общении с родным -> управляемым мы используем COM-объекты. Мы пытаемся применить те же правила в отношении blittable, но мы обнаружили, что вам часто приходится включать много COM-объектов в этот сценарий, который предотвращает blittable-ness.
Принятие такого подхода сработало у нас довольно хорошо. Мы потратили немного времени на получение примитивов, определенных для сортировки данных. Но после этого сортировка стала ... рутиной из-за отсутствия лучшего слова. Это накладные расходы, но это намного дешевле, чем полное переписывание.