减少生成的dll数量
2015-07-27 08:57
302 查看
在开篇之前我想鄙视我自己一下,这个东西根本不需要去写,本来已经有东西去实现了,正如我组长说我的,看的开源项目太少了。其实这个东西完全可以用ILMerge来解决。
然后再说说前言,开发东西久了,总会积累到一定量的Helper或Util,于是都放到一个项目里面一起编一个dll,用的时候就方便,可是问题来了,像SQLite这种Helper需要带上它的dll,再多封装几个类,附带的dll就更多了,有时候想单单用一个很简单的Helper,结果还带了一大堆不相干的dll,会不爽,而且有种感觉是引用时就单纯一个Common.dll就够了,什么System.Data.SQLite.dll,System.Data.MySql.dll我都不想带,在一次使用内嵌资源时给流我灵感,把这堆dll在编译的时候都放到项目资源中,需要的时候就去加载,这样就行了。
单纯这个就用到了内嵌资源使用方面的知识,另外一个就是AppDomain对dll加载方面的知识。
在使用内嵌资源时,要把资源包含在项目里面,内嵌的资源在属性页面上"生成操作"选择"潜入资源",
在编码时要把资源用上,得用流来读取,通过Assembly的GetManifestResourceStream(string name);方法就可以把资源的流获取到,流到了就爱干嘛干嘛,代码如下
dll的流拿到流,使用它的地方就在AppDomain的AssemblyResolve事件,当应用程序域加载外部的程序集时,它会默认往两个地方找,第一是往.NET Framework的目录中找,再到应用程序所在目录中找,所以在默认情况下我们开发的类库都会跟引用程序放到一个目录,而经常用到的System.dll才不需要放到引用程序目录中。那假如需要的dll没办法从这两个地方找到的话,程序会抛出FileNotFoundException异常,这个仍然有办法解决的,其实在抛出FileNotFoundException异常之前,AppDomain会先触发AssemblyResolve事件,这个事件会返回这个无法找到的程序集,返回的程序集为空,才会抛FileNotFoundException异常,只要我们注册了AssemblyResolve事件,在绑定的方法中把dll从资源中取出来,加载上程序集之后,无法在文件目录中找到的程序集就可以加载到程序域中,程序集中的类可以照常使用
代码如下
但是存在一个问题,这个AssemblyResolve事件在封装的Common项目中注册比较合适,可是AssemblyResolve事件应该是主动调用的,而Common里面的类全都是被调用的,个人觉得这个AssemlbyResolve事件可以放到Helper类的静态构造函数里面,此外也暂时想不出更好办法,或者这种方式本身不是一个好的方式。
后续在开发中也发现一个问题,假如这个Common.dll在别的程序集也是通过AssemblyResolve事件被加载到程序域中的时候,这些在Common.dll里面通过AssemlbyResolve事件加载进来的程序集有问题。此问题还暂时无法解释,估计要学习一下CLR方面的知识。
然后再说说前言,开发东西久了,总会积累到一定量的Helper或Util,于是都放到一个项目里面一起编一个dll,用的时候就方便,可是问题来了,像SQLite这种Helper需要带上它的dll,再多封装几个类,附带的dll就更多了,有时候想单单用一个很简单的Helper,结果还带了一大堆不相干的dll,会不爽,而且有种感觉是引用时就单纯一个Common.dll就够了,什么System.Data.SQLite.dll,System.Data.MySql.dll我都不想带,在一次使用内嵌资源时给流我灵感,把这堆dll在编译的时候都放到项目资源中,需要的时候就去加载,这样就行了。
单纯这个就用到了内嵌资源使用方面的知识,另外一个就是AppDomain对dll加载方面的知识。
在使用内嵌资源时,要把资源包含在项目里面,内嵌的资源在属性页面上"生成操作"选择"潜入资源",
在编码时要把资源用上,得用流来读取,通过Assembly的GetManifestResourceStream(string name);方法就可以把资源的流获取到,流到了就爱干嘛干嘛,代码如下
Stream s = null; byte[] dllDatas = null; try { s = Assembly.GetExecutingAssembly().GetManifestResourceStream("ConsoleApplication2.ClassLibrary1.dll"); dllDatas = new byte[s.Length]; s.Read(dllDatas, 0, dllDatas.Length); } catch (Exception ex) { return null; } finally { if (s != null) { s.Close(); s.Dispose(); } }
dll的流拿到流,使用它的地方就在AppDomain的AssemblyResolve事件,当应用程序域加载外部的程序集时,它会默认往两个地方找,第一是往.NET Framework的目录中找,再到应用程序所在目录中找,所以在默认情况下我们开发的类库都会跟引用程序放到一个目录,而经常用到的System.dll才不需要放到引用程序目录中。那假如需要的dll没办法从这两个地方找到的话,程序会抛出FileNotFoundException异常,这个仍然有办法解决的,其实在抛出FileNotFoundException异常之前,AppDomain会先触发AssemblyResolve事件,这个事件会返回这个无法找到的程序集,返回的程序集为空,才会抛FileNotFoundException异常,只要我们注册了AssemblyResolve事件,在绑定的方法中把dll从资源中取出来,加载上程序集之后,无法在文件目录中找到的程序集就可以加载到程序域中,程序集中的类可以照常使用
代码如下
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { Stream s = null; byte[] dllDatas = null; try { s = Assembly.GetExecutingAssembly().GetManifestResourceStream("ConsoleApplication2.ClassLibrary1.dll"); dllDatas = new byte[s.Length]; s.Read(dllDatas, 0, dllDatas.Length); } catch (Exception ex) { return null; } finally { if (s != null) { s.Close(); s.Dispose(); } } Assembly assembly= AppDomain.CurrentDomain.Load(dllDatas); return assembly; }
但是存在一个问题,这个AssemblyResolve事件在封装的Common项目中注册比较合适,可是AssemblyResolve事件应该是主动调用的,而Common里面的类全都是被调用的,个人觉得这个AssemlbyResolve事件可以放到Helper类的静态构造函数里面,此外也暂时想不出更好办法,或者这种方式本身不是一个好的方式。
后续在开发中也发现一个问题,假如这个Common.dll在别的程序集也是通过AssemblyResolve事件被加载到程序域中的时候,这些在Common.dll里面通过AssemlbyResolve事件加载进来的程序集有问题。此问题还暂时无法解释,估计要学习一下CLR方面的知识。
相关文章推荐
- SVN 常用命令
- 自动取款机 软件安装及操作故障总结
- 普元启动时连接超时
- 最小生成树-prim
- 1089-1096
- Linux帮助命令
- 数学_LightOJ_1008
- .net单元测试框架xUnit.net
- Android root漏洞分析汇总
- 设计模式学习笔记十一:观察者模式
- js在方法Ajax请求数据来推断,验证无效(OnClientClick="return Method();"),或者直接运行的代码隐藏
- 修改配置文件之前一定要备份
- QWidget属性,函数的学习
- 设计模式学习笔记十一:观察者模式
- Linux Out-Of-Memory(OOM) Killer分析
- Linux Out-Of-Memory(OOM) Killer分析
- 白皮书是什么意思?
- 请教大家,如何使用sed命令,替换文件指定行的内容呢?-Linux系统管理-ChinaUnix.net
- 网上删除所有数据文件的恢复情况
- 猜数字(规律)