P / Invoke или C ++ / CLI для упаковки библиотеки C - PullRequest
31 голосов
/ 01 апреля 2010

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

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

Проблемы, о которых я мог подумать, могут быть, но не проблематичными:

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

Проблемы, в которых я не уверен:

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

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

Ответы [ 6 ]

15 голосов
/ 01 апреля 2010

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

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

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

7 голосов
/ 02 апреля 2010

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

4 голосов
/ 01 апреля 2010

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

Поскольку оболочка, как правило, очень тонкая, оболочка C ++ / CLI не обязательно должна знать C ++ / CLI. То, что вам нужно знать, можно найти в спецификации языка , это обширная документация с множеством примеров. P / Invoke более приятен в том, чтобы иметь функцию для небольших хорошо существующих существующих библиотек, но если интерфейс для вызова этой библиотеки изменится, вы столкнетесь с проблемой. С C ++ / CLI у вас все еще может быть общедоступный управляемый интерфейс в вашем проекте C ++ / 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
2 голосов
/ 01 апреля 2010

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

2 голосов
/ 01 апреля 2010

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

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

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

0 голосов
/ 01 апреля 2010

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

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

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

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

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

...