在C++中加载和卸载DLL是一件很容易的事LoadLibrary和FreeLibrary让你能够轻易的在程序中加载DLL然后在任何地方卸载在C#中我们也能使用AssemblyLoadFile实现动态加载DLL但是当你试图卸载时你会很惊讶的发现Assembly没有提供任何卸载的方法这是由于托管代码的自动垃圾回收机制会做这件事情所以C#不提供释放资源的函数一切由垃圾回收来做
这引发了一个问题用Assembly加载的DLL可能只在程序结束的时候才会被释放这也意味着在程序运行期间无法更新被加载的DLL而这个功能在某些程序设计时是非常必要的考虑你正在用反射机制写一个查看DLL中所有函数详细信息的程序程序提供一个菜单让用户可以选择DLL文件这时就需要让程序能够卸载DLL否则一旦用户重新得到新版本DLL时必须要重新启动程序重新选择加载DLL文件这样的设计是用户无法忍受的
C#也提供了实现动态卸载DLL的方法通过AppDomain来实现AppDomain是一个独立执行应用程序的环境当AppDomain被卸载的时候在该环境中的所有资源也将被回收关于AppDomain的详细资料参考MSDN下面是使用AppDomain实现动态卸载DLL的代码
using System;
using SystemCollectionsGeneric;
using SystemText;
using SystemThreading;
using SystemReflection;
namespace UnloadDll
{
class Program
{
static void Main(string[] args)
{
string callingDomainName = AppDomainCurrentDomainFriendlyName;//ThreadGetDomain()FriendlyName;
ConsoleWriteLine(callingDomainName);
AppDomain ad = AppDomainCreateDomain(DLL Unload test);
ProxyObject obj = (ProxyObject)adCreateInstanceFromAndUnwrap(@UnloadDllexe UnloadDllProxyObject);
objLoadAssembly();
objInvoke(TestDllClass Test Its a test);
AppDomainUnload(ad);
obj = null;
ConsoleReadLine();
}
}
class ProxyObject : MarshalByRefObject
{
Assembly assembly = null;
public void LoadAssembly()
{
assembly = AssemblyLoadFile(@TestDLLdll);
}
public bool Invoke(string fullClassName string methodName params Object[] args)
{
if(assembly == null)
return false;
Type tp = assemblyGetType(fullClassName);
if (tp == null)
return false;
MethodInfo method = tpGetMethod(methodName);
if (method == null)
return false;
Object obj = ActivatorCreateInstance(tp);
methodInvoke(obj args);
return true;
}
}
}
注意
要想让一个对象能够穿过AppDomain边界必须要继承MarshalByRefObject类否则无法被其他AppDomain使用
每个线程都有一个默认的AppDomain可以通过ThreadGetDomain()来得到