AppDomain与Assembly的动态加载与卸载

简介: 为了将问题描述清楚,我们先来看一个例子。在这个例子中,WinForm上有一个按钮,当用户点击这个按钮后,就会装载一个已经存在的Assembly,并且在界面的Label控件上显示出这个Assembly的FullName。

为了将问题描述清楚,我们先来看一个例子。在这个例子中,WinForm上有一个按钮,当用户点击这个按钮后,就会装载一个已经存在的Assembly,并且在界面的Label控件上显示出这个Assembly的FullName。对Reflection稍微熟悉一点的朋友都知道,这是非常简单的事情,只需要用Assembly.LoadFile方法获得Assembly,然后用FullName属性来显示即可,比如下面的代码:

  1. privatevoidbutton1_Click(objectsender,EventArgse)
  2. {
  3. Assemblyassembly=Assembly.LoadFile(@"C:\testlib.dll");
  4. label1.Text=assembly.FullName;
  5. }

当然,程序执行正常,您不会发现任何编译时或运行时的错误。然而,当你在没有退出此程序之前,再去编译被调用的testlib.dll,你会发现,Visual Studio无法完成编译,提示说该文件正在被其它的进程所使用。

事实上,我们的程序与这个testlib.dll并没有太大的关联,我们的程序只不过就是显示一下testlib.dll的基本信息。如果testlib.dll是一个共享的库,那么资源独占问题会影响到其它程序的正常工作。

Assembly没有Unload的功能,但可以使用AppDomain来解决这个问题。基本思路是,创建一个新的AppDomain,在这个新建的AppDomain中装载assembly,调用其中的方法,然后将获得的结果返回。在完成所有操作以后,调用AppDomain.Unload方法卸载这个新建的AppDomain,这样也同时卸载了assembly。注意:你无法将装载的assembly直接返回到当前应用程序域(AppDomain)。

首先,创建一个RemoteLoader,这个RemoteLoader用于在新建的AppDomain中装载assembly,并向外公布一个属性,以便外界能够获得assembly的FullName。RemoteLoader需要继承于MarshalByRefObject。代码如下:

  1. publicclassRemoteLoader:MarshalByRefObject
  2. {
  3. privateAssemblyassembly;
  4. publicvoidLoadAssembly(stringfullName)
  5. {
  6. assembly=Assembly.LoadFrom(fullName);
  7. }
  8. publicstringFullName
  9. {
  10. get{returnassembly.FullName;}
  11. }
  12. }

其次,创建一个LocalLoader。LocalLoader的功能是创建新的AppDomain,然后在这个新的AppDomain中调用RemoteLoader,以便通过RemoteLoader来创建assembly并获得assembly的相关信息。此时被调用的assembly自然被装载于新的AppDomain中。最后,LocalLoader还需要提供一个新的方法,就是AppDomain的卸载。代码如下:

  1. publicclassLocalLoader
  2. {
  3. privateAppDomainappDomain;
  4. privateRemoteLoaderremoteLoader;
  5. publicLocalLoader()
  6. {
  7. AppDomainSetupsetup=newAppDomainSetup();
  8. setup.ApplicationName="Test";
  9. setup.ApplicationBase=AppDomain.CurrentDomain.BaseDirectory;
  10. setup.PrivateBinPath=Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"private");
  11. setup.CachePath=setup.ApplicationBase;
  12. setup.ShadowCopyFiles="true";
  13. setup.ShadowCopyDirectories=setup.ApplicationBase;
  14. appDomain=AppDomain.CreateDomain("TestDomain",null,setup);
  15. stringname=Assembly.GetExecutingAssembly().GetName().FullName;
  16. remoteLoader=(RemoteLoader)appDomain.CreateInstanceAndUnwrap(
  17. name,
  18. typeof(RemoteLoader).FullName);
  19. }
  20. publicvoidLoadAssembly(stringfullName)
  21. {
  22. remoteLoader.LoadAssembly(fullName);
  23. }
  24. publicvoidUnload()
  25. {
  26. AppDomain.Unload(appDomain);
  27. appDomain=null;
  28. }
  29. publicstringFullName
  30. {
  31. get
  32. {
  33. returnremoteLoader.FullName;
  34. }
  35. }
  36. }

最后,修改我们WinForm上的Button Click事件处理过程,改为如下的形式:

  1. privatevoidbutton1_Click(objectsender,EventArgse)
  2. {
  3. LocalLoaderll=newLocalLoader();
  4. ll.LoadAssembly(@"C:\testlib.dll");
  5. label1.Text=ll.FullName;
  6. ll.Unload();
  7. }

在完成上述的修改后,我们的程序也同样能够正确地显示assembly的FullName,而且,在显示完assembly信息后,程序会主动卸载新建的AppDomain,以防止testlib.dll的资源独占,影响其它程序的运行。

参考:http://www.microsoft.com/china/msdn/library/langtool/vcsharp/csharp05162002.mspx?mfr=true

目录
相关文章
|
4月前
|
存储 Java C语言
Windows 下 JNI 调用动态链接库 dll
Windows 下 JNI 调用动态链接库 dll
70 0
|
8月前
|
开发框架 .NET Java
C#下反射动态加载dll后如何卸载?
C#下反射动态加载dll后如何卸载?
|
10月前
.Net6新版本的AssemblyLoadContext 加载程序集和卸载程序集
.Net6新版本的AssemblyLoadContext 加载程序集和卸载程序集
101 0
.Net6新版本的AssemblyLoadContext 加载程序集和卸载程序集
C#.Net 如何动态加载与卸载程序集(.dll或者.exe)6-----在不卸载程序域的前提下替换程序集文件。
原文:C#.Net 如何动态加载与卸载程序集(.dll或者.exe)6-----在不卸载程序域的前提下替换程序集文件。 当某个程序集文件被载入AppDomain,该文件在AppDomain.Unload之前是不能被替换和删除的。
2316 0
|
C# C++
C#中动态加载和卸载DLL
原文:C#中动态加载和卸载DLL 在C++中加载和卸载DLL是一件很容易的事,LoadLibrary和FreeLibrary让你能够轻易的在程序中加载DLL,然后在任何地方卸载。在C#中我们也能使用Assembly.LoadFile实现动态加载DLL,但是当你试图卸载时,你会很惊讶的发现Assembly没有提供任何卸载的方法。
2223 0
|
C#
c#实现动态加载Dll
原文:c#实现动态加载Dll 原理如下: 1、利用反射进行动态加载和调用. Assembly assembly=Assembly.
2561 0
|
Android开发 iOS开发 图形学