Assembly.Load动态加载程序集而不占用文件

方式一:占用文件的加载

Assembly assembly = Assembly.Load(path);

用上面的方法可以动态的加载到dll,但是用这种方法加载到的dll一直到程序运行结束都是占用的dll文件,在此期间不能够对dll文件进行升级,或者修改.

方式二:不占用文件的方式

Assembly ab = Assembly.Load(File.ReadAllBytes(path)); 

首先把dll加载到内存中,然后在在加载成Assembly ,这样的话,dll完全跟程序解耦了,只要加载完成,你就是把dll给删除了,程序也一样照常运行。

       有时候,需要将被引用的程序集放到单独的目录统一维护(如更新等),提供给多个项目使用到这些程序集。

我们知道,项目在添加了对程序集的引用后,编译时通常会将引用的程序集一起生成到bin或release目录。现在为了统一管理,我们把这些要引用的程序 集放到一个公共的目录,供多个项目使用,同时我们移除掉bin或release目录下的这些dll文件。默认情况下,程序运行过程中需要加载一个程序集, 会先后从系统目录和程序运行目录查找要加载的dll文件,如果都没有查找到,将会抛出一个异 常:System.IO.FileNotFoundException: 未能加载文件或程序集“Accessibility, Version=x.x.x.x, Culture=neutral, PublicKeyToken=xxxxxx”或它的某一个依赖项。系统找不到指定的文件。

现在我们通过注册AppDomain.CurrentDomain.AssemblyResolve事件,在事件处理程序中根据args.Name和我们指定的目录重新构建dll文件路径,加载程序集并返回。这样实现在程序集加载不成功的情况下,转到我们指定的目录加载程序集。

以下代码即实现运行时控制从指定路径加载dll:

   直接将DLL文件添加到资源文件里,保存之后实现如下代码:

 

 

 static void Main()
        {
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
            
        }

        static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            try
            {
                string dllName = args.Name.Contains(",") ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll", "");
                dllName = dllName.Replace(".", "_");
                if (dllName.EndsWith("_resources")) return null;
                System.Resources.ResourceManager rm = new System.Resources.ResourceManager(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());
                byte[] bytes = (byte[])rm.GetObject(dllName);
                Debug.WriteLine(dllName);
                return Assembly.Load(bytes);
            }
            catch
            {
                throw;
            }
        }

 如果加载的窗体是非标准窗体(不是继承Form)提前检测main()内的代码使用的引用资源,而不是执行到该行代码时才检查相关引用资源,于是在main中调用另一个func避开检测

  /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Run();
        }
        static void Run()
        {
            Application.Run(new Form1());
        }

 也可以读取文件流写到指定文件夹进行读取。

 static void Main()
        {
            try
            {
                byte[] buffer = Properties.Resources.HPSocket4C;//这个是添加EXE到程序资源时的名称  
                FileStream FS = new FileStream(Application.StartupPath + @"\HPSocket4C.dll", FileMode.Create);//新建文件  
                BinaryWriter BWriter = new BinaryWriter(FS);//以二进制打开文件流  
                BWriter.Write(buffer, 0, buffer.Length);//从资源文件读取文件内容,写入到一个文件中  
                BWriter.Close();
                FS.Close();
            }
            catch
            { }
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new FrmHttpServer());
        }
        static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            try
            {
                string dllName = args.Name.Contains(",") ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll", "");
                dllName = dllName.Replace(".", "_");
                if (dllName.EndsWith("_resources")) return null;
                System.Resources.ResourceManager rm = new System.Resources.ResourceManager(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());
                byte[] bytes = (byte[])rm.GetObject(dllName);
                return Assembly.Load(bytes);
            }
            catch
            {
                throw;
            }
        }

 

posted @ 2021-05-07 17:20  是晚安呀  阅读(658)  评论(0编辑  收藏  举报