为了将问题描述清楚,我们先来看一个例子。在这个例子中,WinForm上有一个按钮,当用户点击这个按钮后,就会装载一个已经存在的Assembly,并且在界面的Label控件上显示出这个Assembly的FullName。对Reflection稍微熟悉一点的朋友都知道,这是非常简单的事情,只需要用Assembly.LoadFile方法获得Assembly,然后用FullName属性来显示即可,比如下面的代码:
- privatevoidbutton1_Click(objectsender,EventArgse)
- {
- Assemblyassembly=Assembly.LoadFile(@"C:\testlib.dll");
- label1.Text=assembly.FullName;
- }
当然,程序执行正常,您不会发现任何编译时或运行时的错误。然而,当你在没有退出此程序之前,再去编译被调用的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。代码如下:
- publicclassRemoteLoader:MarshalByRefObject
- {
- privateAssemblyassembly;
-
- publicvoidLoadAssembly(stringfullName)
- {
- assembly=Assembly.LoadFrom(fullName);
- }
-
- publicstringFullName
- {
- get{returnassembly.FullName;}
- }
- }
其次,创建一个LocalLoader。LocalLoader的功能是创建新的AppDomain,然后在这个新的AppDomain中调用RemoteLoader,以便通过RemoteLoader来创建assembly并获得assembly的相关信息。此时被调用的assembly自然被装载于新的AppDomain中。最后,LocalLoader还需要提供一个新的方法,就是AppDomain的卸载。代码如下:
- publicclassLocalLoader
- {
- privateAppDomainappDomain;
- privateRemoteLoaderremoteLoader;
-
- publicLocalLoader()
- {
- AppDomainSetupsetup=newAppDomainSetup();
- setup.ApplicationName="Test";
- setup.ApplicationBase=AppDomain.CurrentDomain.BaseDirectory;
- setup.PrivateBinPath=Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"private");
- setup.CachePath=setup.ApplicationBase;
- setup.ShadowCopyFiles="true";
- setup.ShadowCopyDirectories=setup.ApplicationBase;
-
- appDomain=AppDomain.CreateDomain("TestDomain",null,setup);
- stringname=Assembly.GetExecutingAssembly().GetName().FullName;
- remoteLoader=(RemoteLoader)appDomain.CreateInstanceAndUnwrap(
- name,
- typeof(RemoteLoader).FullName);
- }
-
- publicvoidLoadAssembly(stringfullName)
- {
- remoteLoader.LoadAssembly(fullName);
- }
-
- publicvoidUnload()
- {
- AppDomain.Unload(appDomain);
- appDomain=null;
- }
-
- publicstringFullName
- {
- get
- {
- returnremoteLoader.FullName;
- }
- }
- }
最后,修改我们WinForm上的Button Click事件处理过程,改为如下的形式:
- privatevoidbutton1_Click(objectsender,EventArgse)
- {
- LocalLoaderll=newLocalLoader();
- ll.LoadAssembly(@"C:\testlib.dll");
- label1.Text=ll.FullName;
- ll.Unload();
- }
在完成上述的修改后,我们的程序也同样能够正确地显示assembly的FullName,而且,在显示完assembly信息后,程序会主动卸载新建的AppDomain,以防止testlib.dll的资源独占,影响其它程序的运行。
参考:http://www.microsoft.com/china/msdn/library/langtool/vcsharp/csharp05162002.mspx?mfr=true
分享到:
相关推荐
C#也提供了实现动态卸载DLL的方法,通过AppDomain来实现。AppDomain是一个独立执行应用程序的环境,当AppDomain被卸载的时候,在该环境中的所有资源也将被回收。
范例 Appdomain动态加载及数据交互范例
目前对于 Assembly, CLR 没有提供卸载 Assembly 的方法。而 Assembly 是 驻留在 Appdomain 中,Appdomain 是可以动态卸载和创建的。
使用appDomain动态卸载dll.实现资源的释放.
.NET诞生以来,程序集的动态加载和卸载都是一个Hack的技术,之前的NetFx都是使用AppDomain的方式去加载程序集,然而AppDomain并没有提供直接卸载一个程序集的API,而是要卸载整个AppDomain才能卸载包含在其中的所有...
也可以使用插件管理域进行动态装载\执行方法\卸载程序域 但日常工作中还是习惯对所有项目引用一个公共的项目(主要是设计接口\枚举),使用插件时并不喜欢用InvokeMember.而是更多的转换为接口进行调用.这样在接口改动...
利用AppDomain实现对DLL的动态加载和卸载。
考虑使用可热插拔模块编写应用程序时应了解的事项。
运行一个.NET应用程序或者运行库宿主时,OS会首先建立一个进程,然后会在进程中加载CLR(这个加载一般是通过调用_CorExeMain或者_CorBindToRuntimeEx方法来实现),在加载CLR时会创建一个默认的AppDomain,它是CLR的...
本文实例讲述了C#实现动态加载dll的方法。分享给大家供大家参考。具体实现方法如下: 代码如下: using System; using System.Collections.Generic; using System.Text; using System.Reflection; using System.IO; ...
关于AppDomain编程的全面资料,适合中高级技术人员阅读
在AppDomain捕获异常并处理的例子,详见blog.csdn.net/fuadam/
简单的动态调用dll及 dll的释放,运用了AppDomain——应用程序域
最大的区别是.NET Core公开了 ,它与AppDomain有一些重叠,但是是一个重量轻得多的子系统。 资源:本文档介绍了一组方案,并提供了指导和用于实现这些方案的示例。AssemblyLoaderContext程序集加载模型您需要了解新...
clrinject将C#EXE或DLL程序集注入任何其他进程的CLR运行时和AppDomain中。 然后,注入的程序集可以访问注入者进程的类的静态实例,从而影响其内部状态...附加选项-e枚举所有已加载的CLR运行时和创建的AppDomain。 -d我
使用AppDomain实现不重启进程的dll的重复加载
本文比较深入地讨论了ASP.NET程序的工作过程,解释了ASP.NET程序的加载原理。为动态网页设计和开发B/S模式的程序奠定基础
主要项目是 PoC.AppDomainWCF.App,它承载 WCF 服务并包含 Manager 类以创建新的 AppDomains 并将程序集加载到其中。 PoC.AppDomainWCF.WinClient 和 PoC.AppDomainWCF.WPFClient 只是测试跨 AppDomain 通信的简单...
MEF在AppDomain中演示在AppDomain中使用MEF并允许在应用程序运行时交换MEF零件。 这是我有关此主题的博客条目的源代码:和文章: