Загрузить DLL, создать экземпляр и выгрузить - PullRequest
4 голосов
/ 12 августа 2011

У меня есть приложение, которое копирует DLL (UserControlLibrary) в свою собственную папку Debug / Release и загружает ее, используя этот код:

AppDomain appDomain = AppDomain.CreateDomain("MyDomain");
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = "DLLs (*.dll)|*.dll";
if (dialog.ShowDialog().Value)
{
    string newLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\" + dialog.SafeFileName;
    File.Copy(dialog.FileName, newLocation, true);
    Assembly assembly = appDomain.Load(AssemblyName.GetAssemblyName(newLocation));
    UserControl userControl = (UserControl) assembly.CreateInstance("WpfControlLibrary1.UserControl1");
}

Теперь я добавляю этот UserControl в Grid, используя:

grid.Children.Add(userControl);

Работает нормально. Теперь я пытаюсь выгрузить DLL, используя:

AppDomain.Unload(appDomain);
grid.Children.Clear();

Если я сейчас попытаюсь снова загрузить DLL (потому что она изменилась), используя приведенный выше код, я получаю сообщение об ошибке, сообщающее, что файл используется (File.Copy).

Я много чего прочитал, и я предполагаю, что мне не разрешено использовать UserControl, как я (потому что он загружается в основной домен приложения). Как мне изменить код, чтобы он работал?

Я также много читал об использовании MarshalByRefObject, но, к сожалению, я не смог реализовать его в этом проекте. Пример или модификация приведенного выше кода было бы неплохо.

EDIT:

Из комментариев, которые я читал до сих пор (особенно из svick), похоже, что я должен использовать "AppDomain.CreateInstanceAndUnwrap" вместо "AppDomain.Load". Я уже видел этот подход при поиске решения ранее, но, как уже упоминал svick, он не работает, потому что UserControl не может наследовать от MarshalByRefObject.

Кто-нибудь знает другой путь?

Ответы [ 3 ]

2 голосов
/ 12 августа 2011

Чтение документации для AppDomain.Load().В частности, говорится, что этот метод загружает сборку обоих в сборку, для которой вызывается метод, и в текущую сборку.Поэтому, даже когда вы выгружаете домен приложения, сборка все еще остается загруженной в текущей сборке.

Я не уверен, что есть способ обойти это, поскольку вы не можете UserControl наследовать от MarhshalByRefObject.

1 голос
/ 12 августа 2011

Когда вы вызываете unload, домен приложения не сразу выгружается ( полный текст статьи см. В MSDN ):

Когда поток вызывает Unload, целевой доменпомечен для выгрузки. Выделенный поток пытается выгрузить домен, и все потоки в домене прерываются.Если поток не прерывает работу, например, из-за выполнения неуправляемого кода или из-за выполнения блока finally, через некоторое время выдается исключение CannotUnloadAppDomainException ...

0 голосов
/ 12 августа 2011

Возможно, эта цитата из статьи MSDN для AppDomain.Unload могла бы объяснить:

В .NET Framework версии 2.0 есть ветка, посвященная выгрузке доменов приложений. Это повышает надежность, особенно когда размещается .NET Framework. Когда поток вызывает Unload, целевой домен помечается для выгрузки. Выделенный поток пытается выгрузить домен, и все потоки в домене прерываются. Если поток не прерывается, например, потому что он выполняет неуправляемый код или потому, что он выполняет блок finally, то через некоторое время в потоке, первоначально вызвавшем Unload, создается исключение CannotUnloadAppDomainException. Если поток, который не может быть прерван, в конце концов заканчивается, целевой домен не выгружается. Таким образом, в домене .NET Framework версии 2.0 не гарантируется выгрузка домена, поскольку может быть невозможно прервать выполнение потоков.

Может быть, существуют некоторые мошеннические потоки, которые поддерживают работу домена приложения и, следовательно, также сохраняют ваш файл заблокированным.

В качестве обходного пути вы можете вместо этого скопировать библиотеки DLL в произвольные имена файлов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...