dotnet程序的动态加载二:应用程序域
例一:dotnet程序的动态加载一:Assembly.Load 说了运行时无法更新dll,那是不是有其他办法能做到呢?答案自然是应用程序域。
Assembly只有Load,没有UnLoad,库并加载到当前程序域后没法卸载,但程序域可以卸载。当然主程序的程序域卸载的程序也就不存在了,为此我们要在当前程序域中创建创建新的程序域
那是不是有了这个程序域后就能象例一去加载HelloLibrary.dll呢?
object obj = assembly.CreateInstance(className);
不行!这样加载的话,程序集是在新的程序域还是当前程序域,我搞不清。感觉是当前程序域也加载了。因为就算Upload(appDomai),assembly还能用!这也相当于造成当前程序域加载HelloLibrary.dll。这样说对吗?且这样说吧,大家还可以做个试验,以上代码创建对象后,就算
HelloLibrary.dll也无法更新。好了,那该怎么做呢?
需要用一个代理类(继承自System.MarshalByRefObject),且该代理类不能与被加载的类放同一个类库,为此,我创建一个名为RemoteDo的类,并把他放在DomainBase类库。

{
private IDo myDo;
/// <summary>
/// 加载对象
/// </summary>
/// <param name="pAssemblyName"></param>
/// <param name="pClassName"></param>
public void LoadAssembly(string pAssemblyName,string pClassName)
{
myDo = buildDoActor(pAssemblyName, pClassName);
}
private DomainBase.IDo buildDoActor(string pAssemblyName, string pClassName)
{
Assembly assembly = Assembly.Load(pAssemblyName);
object obj = assembly.CreateInstance(pClassName);
if (obj == null)
return null;
return obj as DomainBase.IDo;
}
/// <summary>
/// 执行对象的SayHello
/// </summary>
/// <returns></returns>
public string SayHello()
{
if (myDo == null)
return "指定的类未实现IDO";
else
return myDo.SayHello();
}
}
何为是代理类呢?
代理类的意思是由主程序域使用,而实际的执行过程却是在其他程序域。
那怎么样才能成为代理类的?
上面的RemoteDo类继承自System.MarshalByRefObject是成为代理类的第一个条件,此外还要使用CreateInstanceFromAndUnwrap创建RemoteDo实例
myDo成为一个代理类的实例。主程序域创建这个实例后,如何用呢?以下一段在windows窗体加了一个名为btnDomain的Button,他的点击将创建新的程序域,并使用代理类动态调用程序集。
使用应用程序域加载{
System.AppDomain appDomain = System.AppDomain.CreateDomain("ApplicationDomainTest");
sayHelloByRemoteDo(appDomain);
AppDomain.Unload(appDomain);
}
private void sayHelloByRemoteDo(System.AppDomain appDomain)
{
string assemblyName = "HelloLibrary";//实际情况应从配置中获取。
string className = "HelloLibrary.Hello";//实际情况应从配置中获取。
//取代理类
DomainBase.RemoteDo myDo = appDomain.CreateInstanceFromAndUnwrap("DomainBase.dll", "DomainBase.RemoteDo") as DomainBase.RemoteDo;
if (myDo == null)
{
this.addLog("未能创建代理类");
return ;
}
//在新建的程序域中加载实现的类库
myDo.LoadAssembly(assemblyName, className);
string words = myDo.SayHello();
this.addLog(words);
}
为了验证例一没有完成的任务,我们可以将例一的HelloLibrary.dll拷贝到其他地方。修改Hello.cs
{
return "Hello. I am HelloLibray.Hello, v2.0.";
}
结尾的版本号从“1.0”改为“2.0”。
好了,编译各项目,运行windows程序,点击btnDomain,看到“Hello. I am HelloLibray.Hello, v2.0.”后,把例一的HelloLibrary.dll拷贝到运行目录(不需关闭windows的测试程序),再点击btnDomain看看,是不是变成了“Hello. I am HelloLibray.Hello, v1.0.”
这有一个程序域卸载的文章,大家可以看看。不过文章的代理类返回一个Assembly,我觉得不妥当,但说到了不少卸载相关的内容。
通过应用程序域AppDomain加载和卸载程序集
http://www.cnblogs.com/wayfarer/archive/2004/09/29/47896.html

浙公网安备 33010602011771号