dotnet程序的动态加载二:应用程序域

例一:dotnet程序的动态加载一:Assembly.Load 说了运行时无法更新dll,那是不是有其他办法能做到呢?答案自然是应用程序域。


Assembly只有Load,没有UnLoad,库并加载到当前程序域后没法卸载,但程序域可以卸载。当然主程序的程序域卸载的程序也就不存在了,为此我们要在当前程序域中创建创建新的程序域

System.AppDomain appDomain = System.AppDomain.CreateDomain("ApplicationDomainTest");

 

那是不是有了这个程序域后就能象例一去加载HelloLibrary.dll呢?

Assembly assembly = Assembly.Load(assemblyName);
object obj = assembly.CreateInstance(className);

不行!这样加载的话,程序集是在新的程序域还是当前程序域,我搞不清。感觉是当前程序域也加载了。因为就算Upload(appDomai),assembly还能用!这也相当于造成当前程序域加载HelloLibrary.dll。这样说对吗?且这样说吧,大家还可以做个试验,以上代码创建对象后,就算

AppDomain.Unload(appDomain);

 

HelloLibrary.dll也无法更新。好了,那该怎么做呢?


需要用一个代理类(继承自System.MarshalByRefObject),且该代理类不能与被加载的类放同一个类库,为此,我创建一个名为RemoteDo的类,并把他放在DomainBase类库。

public class RemoteDo : System.MarshalByRefObject
{
    
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实例

DomainBase.RemoteDo myDo = appDomain.CreateInstanceFromAndUnwrap("DomainBase.dll""DomainBase.RemoteDo"as DomainBase.RemoteDo;

 

myDo成为一个代理类的实例。主程序域创建这个实例后,如何用呢?以下一段在windows窗体加了一个名为btnDomain的Button,他的点击将创建新的程序域,并使用代理类动态调用程序集。

使用应用程序域加载
private void btnDomain_Click(object sender, EventArgs e)
{            
    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

public string SayHello()
{
    
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

posted @ 2010-01-08 11:38  生命体验之kevin-Y  阅读(629)  评论(1编辑  收藏  举报