Имейте умеренный размер (40 нечетных функций) C API, который нужно назвать из проекта C#. Функции логически разбиваются для формирования нескольких классов, которые будут API, представленным остальной части проекта.
Там какие-либо объективные причины состоят в том, чтобы предпочесть P/Invoke или C++ / CLI для совместимости подо что API, с точки зрения устойчивости, пригодности для обслуживания, развертывания...?
Проблемы, о которых я мог думать, который мог бы быть, но не проблематичны:
Проблемы, в которых я не уверен:
Что-нибудь еще?
В случае, когда я работаю с существующей библиотекой C, я предпочитаю PInvoke. PInvoke, хотя временами немного утомительный и хлопотный, представляет собой довольно хорошо изученную технологию, имеющую постоянно растущий набор инструментов и доступную интернет-документацию. Вообще говоря, с какой бы проблемой вы не столкнулись, образец уже доступен в Интернете, или быстрая проверка переполнения стека предоставит решение.
C ++ / CLI - отличная технология, но IMHO его документация ограничена по сравнению с PInvoke для конкретных сценариев взаимодействия. У него также нет инфраструктуры инструментов для решений взаимодействия, которые есть у PInvoke. Добавление сборки C ++ / CLI для сценария, который можно решить с помощью PInvoke, кажется мне слишком дорогостоящим.
С другой стороны, если я работаю с большой библиотекой C ++, я немного больше рассматриваю C ++ / CLI. PInvoke не работает с C ++, и я должен добавить какой-то промежуточный уровень. Либо небольшой слой C, чтобы обернуть все вызовы функций C ++, либо библиотека C ++ / CLI, чтобы заполнить пробел. В этом случае C ++ / CLI мне кажется более естественным.
Здесь много хороших ответов - еще одна перспектива - это план для существующего C API. Аргументы в пользу использования PInvoke включают:
Аргументы в пользу использования C ++ / CLI включают:
В этом случае вы можете начать с C ++ / CLI, а затем все больше и больше переходить на C #
C ++ / CLI будет легче отлаживать, если у вас есть персонал, который знает, как отлаживать C ++. Если вы этого не сделаете, это может быть намного сложнее.
Я бы предположил, что здесь нужно искать компромисс между простотой использования для потребителей вашей сборки взаимодействия и простотой обслуживания самой сборки. Если у вас есть солидное ядро старших инженеров, которые знакомы с C ++ и могут надежно поддерживать сборку, остальной части вашей команды, не знакомой с собственным кодом, будет намного проще предоставить им полностью управляемый интерфейс, который позаботится о все для них.
С другой стороны, если вы единственный человек в магазине, имеющий опыт работы с C ++, я бы с большим подозрением отнесся к встраиванию модуля C ++ в проект, на случай, если кому-то другому придется поддерживать его позже.
Думайте о 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
Для API такого размера (всего около 40 точек входа) я бы провел разделительную линию между C ++ / CLI и P / Invoke в зависимости от того, сколько у вас «мусора из файла заголовка». нужно продублировать на C #. Если это небольшая (или скромная) сумма, подойдет P / Invoke. Как только вы начнете дублировать множество файлов .H на C # - особенно для вещей, которые не представлены в вашем .NET API - вам может быть лучше использовать C ++ / CLI.
Это в значительной степени зависит от того, как обрабатывается владение памятью. P/invoke может маршалить указатели только тогда, когда управление памятью происходит одним из пары определенных способов, обычно это буферы, выделяемые вызывающей стороной. Если ваш API возвращает указатели (через возвращаемое значение или параметр out, неважно) и ожидает, что они будут переданы обратно в функцию уничтожения позже... p/invoke либо сделает автоматическое маршалинг, либо предоставит вам прямой доступ к значению указателя, которое вам нужно отправить обратно позже, но никогда и то, и другое. Так что C++/CLI становится очень желательным подходом в этом случае.