Насколько я понимаю, вы хотите сделать следующее:
- Загрузить сборку с диска, в память, чтобы использовать на ней данные или код вызова в ней
- Позже выгрузить сборку
- Избегайте блокировки сборки на диске, чтобы ее можно было изменить без выхода из приложения (или сначала выгрузить сборку)
По сути, вы описываете систему плагинов, и вы можете сделать это с использованием затененных библиотек dll и приложений.
Во-первых, чтобы выгрузить сборку, не выходя из приложения, вам необходимо загрузить эту сборку в отдельный домен приложения. Вы должны быть в состоянии найти хорошие учебники в сети о том, как это сделать.
Вот запрос Google , который должен предоставить вам несколько начальных статей.
Во-вторых, чтобы не блокировать сборку на диске, все просто, сначала сделайте ее копию и загрузите копию вместо оригинала. Конечно, вы заблокируете копию, но копия - это просто временный файл для вашего приложения, поэтому никто не должен интересоваться изменением этого файла в любом случае. Это оставляет исходный файл разблокированным и изменяемым.
Вы должны попытаться использовать теневое копирование вместо использования перегрузок Assembly.Load
, которые могут загружать сборки из байтового массива, если у вас есть более одной сборки, которая будет загружена и заменена.
Например, если сборка вашего плагина A.dll использует вторую сборку B.dll, и вы используете трюк с байтовым массивом для загрузки A.dll в память перед вызовом Assembly.Load, вам нужно либо обработать вызовы разрешения сборки в домене приложения (вам может быть сказано, когда сборка должна быть загружена, и «помогите» процессу загрузки), или вам нужно убедиться, что B.dll загружается в первую очередь так же, как загружается A.dll, в противном случае загрузка A .dll из памяти автоматически загрузит B.dll с диска.
Вот еще немного информации об использовании отдельных доменов приложений.
Когда вы создаете другой домен приложения, используя класс AppDomain в .NET, вы создаете отдельное отделение в памяти, где вы можете запускать код. Он действительно отделен от вашего основного домена приложения и имеет лишь небольшую дыру в стене, которая разделяет их.
Через эту дыру вы можете передавать сообщения, такие как вызовы методов и данные.
После создания нового домена приложения вы загружаете в него одну или несколько сборок. Как правило, вы загружаете 1, если сборка, в которую вы хотите загрузить, была построена для этого типа загрузки, или 2, если нет, (подробнее об этом ниже).
После загрузки сборки вы создаете один или несколько объектов внутри этого другого домена приложения таким образом, чтобы первый домен приложения мог общаться с этими объектами. Эти объекты должны происходить от MarshalByRefObject , который является классом, позволяющим произойти некоторой магии.
По сути, так и происходит. Внутри этого другого домена приложения создается объект типа, загруженного в этот домен приложения. Этот тип происходит от MarshalByRefObject . Запрос на создание этого объекта поступил из первого домена приложения, и внутри этого домена приложения создается прокси-объект, который похож на тот же объект, который был создан в этом другом домене приложения, но не похож на него. Прокси разговаривает с этим другим объектом через эту дыру.
Итак, теперь у вас есть два домена приложений и два объекта, по одному на каждой стороне, и объекты общаются друг с другом.
С этой настройкой позже вы можете разорвать соединение между объектами, а затем выгрузить этот другой домен приложения, который в основном разрушает этот отсек. Затем, при желании, вы можете создать новый второй домен приложения и начать заново, фактически перезагрузив сборки с диска.
Одна вещь, на которую нужно обратить внимание, это данные, которые вы проходите через эту дыру. Если какие-либо данные, которые вы передаете через это отверстие, являются объектом, который объявлен в загруженной вами сборке (сборке вашего плагина или расширения), то вы не только вернете этот объект обратно в основной домен приложения, но и в основной домен приложения. загрузите эту сборку в свой собственный домен и, таким образом, сделайте невозможным правильную связь со вторым доменом приложения после перезагрузки.
Поэтому убедитесь, что вы этого не делаете, передаете собственные типы или типы, которые определены вне сборок, которые вы хотите заменить.
Я упоминал, что вы можете загрузить как минимум две сборки. Причина этого заключается в том, что если тип, для которого вы хотите создать объект, тип, который объявлен в той сборке, которую вы хотите загрузить, не происходит от MarshalByRefObject , то проблема передачи типов через это отверстие снова появится, и вы также загрузите сборку в свой основной домен. Типичный способ справиться с этим - иметь некоторый класс менеджера плагинов, который происходит от MarshalByRefObject , и этот менеджер должен находиться в этом другом домене и общаться с этими другими типами. Это позволяет избежать проблемы прохождения типов через это отверстие.
Я уже некоторое время бродил здесь, так что я оставлю это так, но с этой информацией вы сможете понять и использовать статьи, найденные с помощью этого запроса Google, немного проще.