读取Assembly时如何不让DLL锁定在用Assembly.Load 或者Assembly.Loadfrom读取dll时,dll将被锁定,也就是该
读取Assembly时如何不让DLL锁定
在用Assembly.Load 或者Assembly.Loadfrom读取dll时,dll将被锁定,也就是该程序集无法被更新,修改或删除,下面介绍一下如何获取该程序集并使其不被锁定。
(方法一)
首先会创建出两个类,一个Loader一个是RemoteLoader
说明:
1、Loader类提供创建子程序域和卸载程序域的方法;
2、RemoteLoader类提供装载程序集方法;
3、Loader类获得RemoteLoader类的代理对象,并调用RemoteLoader类的方法;
4、RemoteLoader类的方法在子程序域中完成;
5、Loader类和RemoteLoader类均放在AssemblyLoader.dll程序集文件中;
我们再来看代码:
Loader类:
SetRemoteLoaderObject()方法:
??private AppDomain domain = null;
??private Hashtable domains = new Hashtable();??
??private RemoteLoader rl = null;

public?RemoteLoader?SetRemoteLoaderObject(string?dllName)

{

????AppDomainSetup?setup?=?new?AppDomainSetup();????????????

????setup.ShadowCopyFiles?=?"true";

????domain?=?AppDomain.CreateDomain(dllName,null,setup);

????????????

????domains.Add(dllName,domain);????

????try

????{????????????????rl = (AssemblyLoader.RemoteLoader)domain.CreateInstanceFromAndUnwrap(
????????????????"AssemblyLoader.dll","AssemblyLoader.RemoteLoader");?

????????

????}

????catch

????{

????????throw?new?Exception();

????}

}
代码中的变量rl为RemoteLoader类对象,在Loader类中是其私有成员。SetRemoteLoaderObject()方法实际上提供了两个功能,一是创建了子程序域,第二则是获得了RemoteLoader类对象。
请大家一定要注意语句:
rl = (AssemblyLoader.RemoteLoader)domain.CreateInstanceFromAndUnwrap("AssemblyLoader.dll","AssemblyLoader.RemoteLoader");
这条语句就是实现两个程序域之间通讯的关键。因为Loader类是在主程序域中,RemoteLoader类则是在子程序域中。如果我们在Loader类即主程序域中显示实例化RemoteLoader类对象rl,此时调用rl的方法,实际上是在主程序域中调用的。因此,我们必须使用代理的方式,来获得rl对象,这就是CreateInstanceFromAndUnwrap方法的目的。其中参数一为要创建类对象的程序集文件名,参数二则是该类的类型名。
CreateCreateInstanceFromAndUnwrap方法有多个重载。代码中的调用方式是当RemoteLoader类为默认构造函数时的其中一种重载。如果RemoteLoader类的构造函数有参数,则方法应改为:

object[]?parms?=?{dllName};

BindingFlags?bindings?=?BindingFlags.CreateInstance?|

BindingFlags.Instance?|?BindingFlags.Public;

rl?=?(AssemblyLoader.RemoteLoader)domain.CreateInstanceFromAndUnwrap("AssemblyLoader.dll","AssemblyLoader.RemoteLoader",true,bindings,

null,parms,null,null,null);
详细的调用方式可以参考MSDN。
以下Loader类的Unload方法和LoadAssembly方法():

public?Assembly?LoadAssembly(string?dllName)

{

????try

????{

????????SetRemoteLoaderObject(dllName);

????????return?rl.LoadAssembly(dllName);

????}

????catch?(Exception)

????{

????????throw?new?AssemblyLoadFailureException();

????}

}

public?void?Unload(string?dllName)

{

????if?(domains.ContainsKey(dllName))

????{

????????AppDomain?appDomain?=?(AppDomain)domains[dllName];

????????AppDomain.Unload(appDomain);

????????domains.Remove(dllName);

????}????????????

}
当我们调用Unload方法时,则程序域domain加载的程序集也将随着而被卸载。LoadAssembly方法中的异常AssemblyLoadFailureException为自定义异常:

????public?class?AssemblyLoadFailureException:Exception

????{

????????public?AssemblyLoadFailureException():base()

????????{????????????

????????}


????????public?override?string?Message

????????{

????????????get

????????????{

????????????????return?"Assembly?Load?Failure";

????????????}

????????}


????}
既然在Loader类获得的RemoteLoader类实例必须通过代理的方式,因此该类对象必须支持被序列化。所以我们可以令该类派生MarshalByRefObject。RemoteLoader类的代码:

????public?class?RemoteLoader:MarshalByRefObject

????{

????????public?RemoteLoader(string?dllName)

????????{

????????????if?(assembly?==?null)

????????????{

????????????????assembly?=?Assembly.LoadFrom(dllName);

????????????}

????????}????????


????????private?Assembly?assembly?=?null;


????????public?Assembly?LoadAssembly(string?dllName)

????????{

????????????try

????????????{

????????????????assembly?=?Assembly.LoadFrom(dllName);????????????????

????????????????return?assembly;

????????????}

????????????catch?(Exception)

????????????{

????????????????throw?new?AssemblyLoadFailureException();

????????????}

????????}

????}
通过上述的两个类,我们就可以实现程序集的加载和卸载。另外,为了保证应用程序域的对象在内存中被清除,应该令这两个类都实现IDisposable接口,和实现Dispose()方法。
?
在应用时,只需要调用Loader的LoadAssembly方法。
?
(方法二)
只需将该dll 读取到一个字节数组,然后再调用Assembly. Load(),相当于给该dll创建了一个副本。
?
Bye[] content=File.ReadAllBytes(assemblyPath);Assembly assembly=Assembly.Load(content);
?
?
?