代码改变世界

[转载]动态决定加载dll多个版本的完美方案

2007-06-30 22:19  Brush  阅读(726)  评论(0编辑  收藏  举报
  今天看到动态加载DLL的一个不错的实现方案,转载一下。

  原文出处:懒猪乐园 再次感谢作者!!!

  原文:

  

  最近同事遇到一个问题,关于程序需要在动态的时候决定究竟要加载dll的哪个版本.

  我们程序现在依赖于cad的一个simple.dll. cad有2004,有2006.这个simple.dll是强命名的,04跟06虽不同但版本号是一样的,不可以放在同一目录下.我们现在的程序需要同时支持cad 2004,2006.当客户端安装的是Cad2004时我们要用04的simple.dll功能,安装的是cad2006时,使用06的simple.dll.

  我们知道.net提供了一种机制可以保证使用最新版本的dll或者由用户决定想用哪个版本.具体可见 How the Runtime Locates Assemblies.但是这种方案主要用于解决多个版本的问题,明显跟我们遇到的情况有点不同.而且此种方法是由config文件决定的,实际上也是达不到运行时决定加载哪个版本,只能事先配置config文件.

  那么想到的另一种方法就是动态加载.然而动态加载在编译期丧失了类型透明的好处,只能通过Invoke去调用方法.现在需要大量调用simple.dll里的方法,需要额外做的事情就太多了.

  今天在看 蝈蝈俊的:使用VS2005的 ClickOnce 技术实现按需下载组件得到启示,并且尝试后证明是可行了.

  首先我们照样直接add reference "simple.dll",该干嘛就干嘛.
然后我们制造事故,在程序的目录下不放置simple.dll(设置Copy Local 属性false即可),让CLR加载程序集失败,并触发AssemblyResolve 事件,然后我们在此事件里动态加载simple.dll.

AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

 Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
 
{
     Assembly newAssembly 
= null
     
// Get the DLL name from the Name argument.
     string[] nameParts = args.Name.Split(',');
     
string dllName = nameParts[0];
     
try
     
{
         
string path = "";
         
if (condition)
         
{
             path 
= "";
         }

         newAssembly 
= Assembly.LoadFile(path);
     }

     
catch (Exception e)
     
{
         
throw (e);
     }


     
return newAssembly;
 }

 

  用几行代码就可以完美解决了此问题.(PS.我喜欢完美哈,用在这里应该也很恰当:-) 心情愉快地说)