我有一个应用程序将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.Children.Add(userControl);
工作正常。现在我尝试使用以下方法卸载DLL:
AppDomain.Unload(appDomain);
grid.Children.Clear();
如果我现在尝试使用上面的代码再次加载DLL(因为它同时改变了),我会收到一个错误,告诉我该文件正在使用中(File.Copy)。
我已经阅读了很多内容,我的猜测是我不允许像我一样使用UserControl(因为它加载到主AppDomain中)。我如何更改代码才能使其正常工作?
我还阅读了很多关于使用MarshalByRefObject的内容,但不幸的是我无法在这个项目中实现它。上面代码的示例或修改都很不错。
修改
从我到目前为止阅读的评论(特别是来自svick)看起来我必须使用“AppDomain.CreateInstanceAndUnwrap”而不是“AppDomain.Load”。 我早先在搜索解决方案时已经看过这种方法,但正如svick提到的那样,因为UserControl不能从MarshalByRefObject继承而无效。
有没有人知道另一种方式?
答案 0 :(得分:2)
阅读the documentation for AppDomain.Load()
。它特别指出,此方法将程序集 加载到正在调用方法的程序集中,并加载到当前程序集中。因此,即使卸载app域,程序集仍然会在当前程序集中保持加载状态。
我不确定是否有办法解决此问题,因为您无法从UserControl
继承MarhshalByRefObject
。
答案 1 :(得分:1)
当您调用卸载时,AppDomain不会立即卸载(see MSDN for the full article):
当线程调用Unload时,目标域将被标记为卸载。 专用线程尝试卸载域,以及所有线程 域被中止。例如,如果线程没有中止 因为它正在执行非托管代码,或者因为它正在执行a 终于阻止,然后经过一段时间了 抛出CannotUnloadAppDomainException ...
答案 2 :(得分:0)
也许来自MSDN文章AppDomain.Unload的这句话可以解释:
在.NET Framework 2.0版中,有一个专门用于卸载应用程序域的线程。这提高了可靠性,尤其是在托管.NET Framework时。当线程调用Unload时,目标域将标记为卸载。专用线程尝试卸载域,并且域中的所有线程都将中止。如果线程没有中止,例如因为它正在执行非托管代码,或者因为它正在执行finally块,那么在一段时间之后,在最初调用Unload的线程中抛出CannotUnloadAppDomainException。如果最终无法中止的线程结束,则不会卸载目标域。因此,在.NET Framework版本2.0域中不保证卸载,因为它可能无法终止执行线程。
也许有一些流氓线程使应用程序域保持活动状态,因此也会保持文件锁定。
作为一种变通方法,您可以将DLL复制到随机文件名中。