C#动态加载dll 时程序集的卸载问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#动态加载dll 时程序集的卸载问题相关的知识,希望对你有一定的参考价值。
程序是个客户端控制台程序,因为部署在多台电脑上,所以是通过服务端通知客户端更新dll
客户端有多个线程同时调用一个dll里面的方法
var apdomain = AppDomain.CreateDomain(“test.dll”)
我为每个dll创建了一个程序池,并加入缓存,设置缓存时间为5分钟,绑定Cache 的OnRemoveCallback 事件,当这个程序集的缓存失效后,会掉用OnRemoveCallback 释放这个程序集 AppDomain.Unload(apdomain),然后再去服务端比对dll版本,有更新是把dll下载下来替换,
现在的问题就是当这个dll的程序集的缓存失效了,但是另一个线程还在执行这个dll里面的一个方法,还没执行完,这时候调用AppDomain.Unload(apdomain) 虽然没提示异常,但是这个时候那个dll还是被占用的,没发替换
问下各位有没有遇到过这样的问题,你们是怎么解决的呢
如果目标程序集是可执行程序,则可以令新建的域执行该代码,此时,在代码执行中突然卸载域,会从执行线程上引发AppDomainUnloadException异常。
跨应用程序域访问不是一种好的设计思路。本回答被提问者和网友采纳 参考技术B 暂时还没有遇到过这种奇葩问题
C#中如何动态加载和卸载DLL
在C#中我们也能使用Assembly.LoadFile实现动态加载DLL,但是当你试图卸载时,你会很惊讶的发现Assembly没有提供任何卸载的方法。这是由于托管代码的自动垃圾回收机制会做这件事情,所以C#不提供释放资源的函数,一切由垃圾回收来做。powered by 25175.net这引发了一个问题,用Assembly加载的DLL可能只在程序结束的时候才会被释放,这也意味着在程序运行期间无法更新被加载的DLL。而这个功能在某些程序设计时是非常必要的,考虑你正在用反射机制写一个查看DLL中所有函数详细信息的程序,程序提供一个菜单让用户可以选择DLL文件,这时就需要让程序能够卸载DLL,否则一旦用户重新得到新版本DLL时,必须要重新启动程序,重新选择加载DLL文件,这样的设计是用户无法忍受的。C#也提供了实现动态卸载DLL的方法,通过AppDomain来实现。AppDomain是一个独立执行应用程序的环境,当AppDomain被卸载的时候,在该环境中的所有资源也将被回收。关于AppDomain的详细资料参考MSDN。下面是使用AppDomain实现动态卸载DLL的代码,usingSystem;usingSystem.Collections.Generic;usingSystem.Text;usingSystem.Threading;usingSystem.Reflection;namespaceUnloadDllclassProgramstaticvoidMain(string[] args)stringcallingDomainName = AppDomain.CurrentDomain.FriendlyName;//Thread.GetDomain().FriendlyName;Console.WriteLine(callingDomainName);AppDomain ad = AppDomain.CreateDomain("DLL Unload test");ProxyObject obj = (ProxyObject)ad.CreateInstanceFromAndUnwrap(@"UnloadDll.exe","UnloadDll.ProxyObject");obj.LoadAssembly();obj.Invoke("TestDll.Class1","Test","It's a test");AppDomain.Unload(ad);obj =null;Console.ReadLine();classProxyObject : MarshalByRefObjectAssembly assembly =null;publicvoidLoadAssembly()assembly = Assembly.LoadFile(@"TestDLL.dll");publicboolInvoke(stringfullClassName,stringmethodName,paramsObject[] args)if(assembly ==null)returnfalse;Type tp = assembly.GetType(fullClassName);if(tp ==null)returnfalse;MethodInfo method = tp.GetMethod(methodName);if(method ==null)returnfalse;Object obj = Activator.CreateInstance(tp);method.Invoke(obj, args);returntrue;注意:1. 要想让一个对象能够穿过AppDomain边界,必须要继承MarshalByRefObject类,否则无法被其他AppDomain使用。 参考技术A 1、利用反射进行动态加载和调用.Assembly assembly=Assembly.LoadFrom(DllPath); //利用dll的路径加载,同时将此程序集所依赖的程序集加载进来,需后辍名.dll
Assembly.LoadFile 只加载指定文件,并不会自动加载依赖程序集.Assmbly.Load无需后辍名
2、加载dll后,需要使用dll中某类.
Type type=ass.GetType(“TypeName”);//用类型的命名空间和名称获得类型
3、需要实例化类型,才可以使用,参数可以人为的指定,也可以无参数,静态实例可以省略
Object obj = Activator.CreateInstance(type,params[]);//利用指定的参数实例话类型
4、调用类型中的某个方法:
需要首先得到此方法
MethodInfo mi=type.GetMethod(“MehtodName”);//通过方法名称获得方法
5、然后对方法进行调用,多态性利用参数进行控制
mi.Invoke(obj,params[]);//根据参数直线方法,返回值就是原方法的返回值 参考技术B 难道不是自动的吗?
以上是关于C#动态加载dll 时程序集的卸载问题的主要内容,如果未能解决你的问题,请参考以下文章