В C вы можете скомпилировать статическую библиотеку, которая зависит от заголовка C, определяющего несколько функций. Вам не нужно знать, какая библиотека в конечном итоге реализует эти функции, поэтому ваша статическая библиотека может быть независимой от реализации. Пока вы предоставляете действительную реализацию, вы можете связать статическую библиотеку с окончательным исполняемым файлом.
Как я могу сделать что-то подобное на С#? Я хочу создать библиотеку, которая зависит от общего API, который может быть реализован несколькими библиотеками DLL C++. (Чтобы было ясно, я имею в виду динамическую компоновку, а не статическую компоновку, как в моей аналогии выше.) Но для использования DllImport и P/Invoke я должен указать имя DLL. Очевидно, я должен сделать это в какой-то момент, но я хотел бы создать DLL библиотеки классов, которая зависит от API из неуказанной на этом этапе DLL, а затем указать только имя этой неуправляемой DLL в финале. прикладной проект.
@shingo Да, конечно. Вы подразумеваете, что я мог бы вызвать DllImport
с переменной вместо строкового литерала? Но в этих примерах DllImport
не вызывается внутри функции. Я далек от эксперта по С#, поэтому, если можно передать ему переменную, я не знаю, как это сделать.
Нет, я имею в виду, что вы только что сравнили статическую библиотеку на C с динамической библиотекой на C#, что несовместимо. Когда вам нужно использовать DLL в C, вам также необходимо указать ее имя, иначе вам придется использовать LoadLibrary + GetProcAddress.
@shingo А, чтобы было ясно, я хочу динамически связывать библиотеки DLL, а не связывать их статически. Статические библиотеки были просто лучшим примером, который я мог придумать для независимой от реализации стратегии API, хотя я уверен, что динамическая компоновка в C/C++ также допускает то же самое. Аналогия может быть не лучшей, но я думаю, что вопрос ясно объясняет, что я хотел бы сделать на С#.
Имя, которое вы предоставляете [DllImport]
, должно быть постоянным во времени компиляции, поэтому вы не можете передавать здесь «динамическое» значение. Однако вы можете использовать какое-то имя по умолчанию или даже фиктивное имя, а затем преобразовать это имя во время выполнения в допустимую библиотеку, используя NativeLibrary.SetDllImportResolver.
Например, в одном проекте я использую нативную библиотеку C libgphoto
. В Windows я включаю его в дистрибутив предварительно скомпилированным, и так получилось, что нужная мне функциональность разделена между двумя dll с именами «libgphoto2-6.dll» и «libgphoto2_port-12.dll». Однако на linux и macos вы можете установить эту библиотеку из пакета, и все функции будут в библиотеке с именем просто «gphoto».
Итак, я определяю свой импорт, используя имена dll "windows":
private const string LibGPhotoName = "libgphoto2-6";
[DllImport(LibGPhotoName)]
public static extern int gp_widget_get_id(IntPtr widget, out int id);
Но тогда, если я не в Windows, я делаю:
NativeLibrary.SetDllImportResolver(typeof(GPhoto2).Assembly, (name, asm, search) => {
if (name == "libgphoto2-6" || name == "libgphoto2_port-12")
{
return NativeLibrary.Load("gphoto2", asm, search);
}
return IntPtr.Zero;
});
Поэтому, если среда выполнения хочет загрузить собственную библиотеку «libgphoto2-6» или «libgphoto2_port-12», я говорю ей вместо этого загрузить «gphoto2».
Вы можете сделать то же самое в вашем случае.
Знаете ли вы, что DLL — это сокращение от динамической библиотеки?