Подтвердить что ты не робот

P/Invoke или С++/CLI для упаковки библиотеки C

У вас есть API с умеренным размером (40 с лишним) C, который нужно вызывать из проекта С#. Функции логически разбиваются, чтобы сформировать несколько классов, которые будут представлены API для остальной части проекта.

Есть ли какие-либо объективные причины, чтобы предпочесть P/Invoke или С++/CLI для интероперабельности под этим API, с точки зрения надежности, поддержки, развертывания,...?

Вопросы, которые я мог подумать, могут быть, но не являются проблематичными:

  • Для С++/CLI потребуется отдельная сборка, классы P/Invoke могут находиться в основной сборке. (У нас уже есть несколько сборок, и в любом случае будут C-dll, поэтому это не главная проблема).
  • Показатели производительности не кажутся различимыми между этими двумя методами.

Вопросы, о которых я не уверен, следующие:

  • Мое ощущение, что С++/CLI будет легче отлаживать, если есть проблема между операциями, это правда?
  • Знание языков достаточно, чтобы люди знали С# и С++, но знание деталей С++/CLI здесь реже.

Что-нибудь еще?

4b9b3361

Ответ 1

В случае, когда я работаю с существующей библиотекой C, я предпочитаю PInvoke. PInvoke, в то время как немного утомительный и неприятный время от времени, является довольно хорошо понятой технологией, которая имеет постоянно растущий набор инструментов и доступную документацию в Интернете. Вообще говоря, во всех проблемах, с которыми вы столкнулись, уже есть образец, доступный в Интернете, или быстрая проверка обеспечит решение.

С++/CLI - отличная технология, но IMHO ее документация ограничена по сравнению с PInvoke для конкретных сценариев взаимодействия. У него также нет инфраструктуры оснастки для решений interop, которые PInvoke имеет. Добавление сборки С++/CLI для сценария, который можно решить с помощью PInvoke, кажется мне слишком дорогостоящим.

С другой стороны, если я работаю с большой библиотекой С++, я считаю С++/CLI немного больше. PInvoke не работает с С++, и я должен добавить некоторый промежуточный уровень. Либо небольшой C-слой, чтобы обернуть все вызовы функций С++, либо библиотеку С++/CLI, чтобы устранить пробел. С++/CLI чувствует себя немного более естественным для меня в этом случае.

Ответ 2

Во многом зависит от владения памятью. P/invoke может маркеровать указатели только тогда, когда управление памятью является одним из нескольких конкретных способов, обычно буферов, выделенных вызывающим. Если ваш API возвращает указатели (через возвращаемое значение или параметр out, не имеет значения) и ожидает, что их снова вернут в функцию уничтожения... p/invoke либо выполнит автоматическое маршалинг, либо даст вам прямой доступ к указателю значение, которое вам нужно отправить позже, и не оба. Поэтому С++/CLI становится очень желательным в этом случае.

Ответ 3

Подумайте о P/Invoke как вызове платформы, вызываете ли вы что-то вроде Win32 API, который очень дружелюбен P/Invoke или вам нужно предоставить привязки .NET для неуправляемой библиотеки?

Поскольку обертка обычно очень тонкая, С++/CLI-оболочка не требует, чтобы вы знали С++/CLI. Что вам нужно знать, можно найти в спецификация языка, это обширная документация с большим количеством примеров. P/Invoke - более приятная функция для небольших хорошо установленных существующих библиотек, но если интерфейс для вызова в эту библиотеку изменится, вы столкнетесь с проблемой. С С++/CLI вы все равно можете иметь общедоступный управляемый интерфейс в своем проекте С++/CLI, который более легко обнаруживает управляемый код и обрабатывает изменения в C API.

Если вы хотите избавиться от дополнительной DLL, вы всегда можете попробовать ILMerge, но я не уверен, способен ли он обрабатывать смешанные сборки (очевидно а не), но похоже, что можно связать как управляемые, так и неуправляемые файлы *.obj с компоновщиком PlatformSDK следующим образом:

cl.exe /MD /c /clr Unmanaged.cpp
csc.exe /target:module /addmodule:*.obj Managed.cs
link.exe /DLL /LTCG /NOENTRY /CLRIMAGETYPE:IJW *.obj Managed.netmodule

Ответ 4

С++/CLI будет легче отлаживать, если у вас есть персонал, который знает, как отлаживать С++. Если вы этого не сделаете, это может быть намного сложнее.

Я бы предположил, что компромисс между ними - это простота использования для потребителей вашей сборной interop и простота обслуживания для самой сборки. Если у вас есть твердое ядро ​​старших инженеров, которые знакомы с С++ и кто может надежно поддерживать сборку, будет намного проще, если остальная часть вашей команды не знакома с собственным кодом, чтобы дать им полностью управляемый интерфейс, который заботится о все для них.

С другой стороны, если вы единственный человек в магазине с опытом С++, я бы очень не хотел встраивать модуль С++ в проект, если кто-то еще должен его поддерживать позже.

Ответ 5

Для API такого размера (~ 40 общих точек входа) я бы нарисовал разделительную линию между С++/CLI и P/Invoke, исходя из того, сколько вам нужно дублировать "файл заголовка" в С#. Если это небольшая (до скромной) сумма, P/Invoke в порядке. После того, как вы начнете дублировать большое количество файлов .H на С# - особенно для вещей, которые не отображаются в вашем .NET API, вам может быть лучше использовать С++/CLI.

Ответ 6

Здесь есть много хороших ответов - еще одна перспектива - это план существующего C API. Аргументы для использования PInvoke включают:

  • Вам нужно поддерживать API C для совместимость с другими потребителями C
  • Вам нужно сохранить код в C как он большой, и миграция тоже дорогой

Аргументы для использования С++/CLI включают:

  • вы хотите переместить как можно больше кода в CLR

В этом случае вы можете начать с С++/CLI, а затем переместить все больше и больше на С#