У меня есть управляемая dll С++, на которую я ссылаюсь из проекта С#. Проект C# будет скомпилирован как AnyCPU. Есть ли способ скомпилировать 32-разрядную и 64-разрядную версию библиотеки Managed C++ dll, а затем указать проекту C# во время выполнения загрузить правильный вариант в зависимости от используемой архитектуры?
Управляемый C++ и AnyCPU
Ответы (2)
Хитрость в том, чтобы заставить dll AnyCPU играть с dll C++, заключается в том, чтобы во время выполнения убедиться, что сборка не может загрузить dll C++, а затем подписаться на событие AppDomain AssemblyResolve. Когда сборка пытается загрузить dll и терпит неудачу, ваш код имеет возможность определить, какую dll нужно загрузить.
Подписка на событие выглядит примерно так:
System.AppDomain.CurrentDomain.AssemblyResolve += Resolver;
Обработчик события выглядит примерно так:
System.Reflection.Assembly Resolver(object sender, System.ResolveEventArgs args)
{
string assembly_dll = new AssemblyName(args.Name).Name + ".dll";
string assembly_directory = "Parent directory of the C++ dlls";
Assembly assembly = null;
if(Environment.Is64BitProcess)
{
assembly = Assembly.LoadFrom(assembly_directory + @"\x64\" + assembly_dll);
}
else
{
assembly = Assembly.LoadFrom(assembly_directory + @"\x86\" + assembly_dll);
}
return assembly;
}
Я создал простой проект, демонстрирующий, как получить доступ к функциям C++ из dll AnyCPU.
https://github.com/kevin-marshall/Managed.AnyCPU
person
Kevin Marshall
schedule
22.11.2016
Я тоже. Я не уверен, что сделал бы это в продакшене, но это, по крайней мере, жизнеспособная идея. Проголосовал за ноль, чтобы вернуть несправедливость
- person Ivan Krivyakov; 13.05.2017
Спасибо Иван! Я ценю вашу поддержку:)
- person Kevin Marshall; 14.05.2017
Спасибо Иван за комментарий. Я думал о том, что вы сказали, не делая этого в производстве. Итак, я пытаюсь немного поучиться здесь :) Источник вашего комментария касается безопасности? Я понимаю, что это хак, но, насколько я знаю, это один из нескольких способов, которыми я знаю, как реализовать поддержку объявления C# AnyCPU из Managed C++. Единственный другой подход, о котором я знаю, - это использование PInvoke, который, я думаю, страдает от той же проблемы. Я прихожу к выводу, что правильный подход - решить проблему при установке.
- person Kevin Marshall; 15.05.2017
Использование преобразователя сборок для загрузки зависимостей в производственном приложении означает, что пользовательскую логику разрешения зависимостей необходимо будет добавить к каждому инструменту, который работает с вашим кодом: средам модульного тестирования, инструментам покрытия и т. д. В противном случае они не смогут найти все необходимые сборки. Поначалу эта проблема может показаться не такой уж большой проблемой, но она очень быстро становится очень раздражающей. Я работал в компании, вся схема управления версиями библиотек которой была основана на пользовательском распознавателе сборок; они боролись с этим в течение нескольких лет и, наконец, сдались, вернувшись к стандартной загрузке сборки .NET.
- person Ivan Krivyakov; 18.05.2017
На самом деле это не так. Логика разрешения зависимостей инкапсулирована в net dll. Таким образом, любой код C#, зависящий от сетевой dll, может использовать общедоступные объекты в сетевой dll, как и любая другая сетевая dll.
- person Kevin Marshall; 04.08.2018
Что вы подразумеваете под «логикой разрешения, инкапсулированной в сетевой dll»? Например. если вы загрузите его в nUnit, как вы скажете nUnit загрузить правильные зависимости? Подключить преобразователь сборки в классе настройки тестов сборки? Ну да ладно, но теперь вы хотите загрузить его в какой-то анализатор кода... Что тогда? Организация, в которой я работал, крупный инвестиционный банк, пыталась внедрить пользовательскую логику разрешения в масштабах всей компании, управляла ею несколько лет и в конце концов сдалась, так как настоящие неудобства возникали то тут, то там.
- person Ivan Krivyakov; 05.08.2018
Для протокола: мы используем этот метод в производстве уже около 5 лет. Я уверен, что есть сценарии, в которых это громоздко или проблематично, но мы обнаружили, что это достаточно простой, но надежный подход к разработке, модульному тестированию и развертыванию. И да, для модульного тестирования мы делаем именно так, как предлагает Иван, и подключаем наш собственный преобразователь сборки в методе инициализации теста.
- person Darryl; 16.11.2018
Преобразователь сборки инкапсулирован в AnyCPU.dll, поэтому весь клиентский код напрямую зависит только от интерфейса AnyCPU.dll. Если вы посмотрите на исходный код, который я предоставил, в AnyCPU.Test.Develop или AnyCPU.Test.Distribute нет кода разрешения сборки. Если в модульных тестах требуется код преобразователя, это предполагает, что зависимости тестируемого кода не полностью инкапсулированы вдали от клиента.
- person Kevin Marshall; 10.12.2018
Чтобы ответить на вопрос Ивана: ModelInitializer включает раннюю регистрацию метода распознавателя сборки, чтобы AnyCPU.dll мог разрешать свои собственные зависимости.
- person Kevin Marshall; 10.12.2018
Я не знаю, как вы «ссылаетесь» на dll С++ (ссылка на сборку P/Invoke и .net), но в любом случае вы можете поменять местами две версии .dll во время установки.
person
Ventsyslav Raikov
schedule
02.05.2012