Как я понимаю, вы хотите сделать следующее:
- загрузить сборку с диска в память, чтобы использовать данные в нем или код вызова в нем
- Уметь выгружать сборку позже
- Избегайте блокировки сборки на диске, чтобы вы могли ее модифицировать без выхода из приложения (или выгрузить сборка первая)
В принципе, то, что вы описываете, представляет собой систему плагинов, и вы можете сделать это с использованием теневых доменов dll и приложений.
Во-первых, чтобы выгрузить сборку, не выходя из приложения, вам необходимо загрузить эту сборку в отдельный домен приложения. Вы должны уметь находить хорошие учебные пособия в сети о том, как это сделать.
Вот Google query, который должен предоставить вам некоторые исходные статьи.
Во-вторых, чтобы избежать блокировки сборки на диске, это просто, просто сделайте копию первой и загрузите копию вместо оригинала. Конечно, вы заблокируете копию, но копия является только временным файлом для вашего приложения, поэтому никто не должен интересоваться модификацией этого файла. Это оставляет исходный файл разблокированным и модифицируемым.
Вам следует попытаться использовать затенение вместо использования перегрузок 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, немного проще.
Зачем вам это нужно? Почему вы не можете использовать Assembly.Load? –
Я не хочу блокировать загруженную DLL. Я хочу иметь возможность динамически загружать, изменять код, компилировать и перезагружать его снова. –
Тогда измените свой вопрос и спросите об этом, и я отвечу. –