<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      通過應用程序域AppDomain加載和卸載程序集

      微軟裝配車的大門似乎只為貨物裝載敞開大門,卻將卸載工人拒之門外。車門的鑰匙只有一把,若要獲得還需要你費一些心思。我在學習Remoting的時候,就遇到一個擾人的問題,就是Remoting為遠程對象僅提供Register的方法,如果你要注銷時,只有另辟蹊徑。細心的開發員,會發現Visual Studio.Net中的反射機制,同樣面臨這個問題。你可以找遍MSDN的所有文檔,在Assembly類中,你永遠只能看到Load方法,卻無法尋覓到Unload的蹤跡。難道我們裝載了程序集后,就不能再將它卸載下來嗎?

      想一想這樣一個場景。你通過反射動態加載了一個dll文件,如今你需要在未關閉程序的情況下,刪除或覆蓋該文件,那么結果會怎樣?很遺憾,系統會提示你無法訪問該文件。事實上該文件正處于被調用的狀態,此時要對該文件進行修改,就會出現爭用的情況。

      顯然,為程序集提供卸載功能是很有必要的,但為什么微軟在其產品中不提供該功能呢?CLR 產品單元經理(Unit Manager) Jason Zander 在文章 Why isn't there an Assembly.Unload method? 中解釋了沒有實現該功能的原因。Flier_Lu在其博客里(Assembly.Unload)有詳細的中文介紹。文中介紹了解決卸載程序集的折中方法。Eric Gunnerson在文章《AppDomain 和動態加載》中也提到:Assembly.Load() 通常運行良好,但程序集無法獨立卸載(只有 AppDomain 可以卸載)。Enrico Sabbadin 在文章《Unload Assemblies From an Application Domain》也有相關VB.Net實現該功能的相關說明。

      尤其是Flier_Lu的博客里已經有了很詳細的代碼。不過,這些代碼沒有詳細地說明。我在我的項目中也需要這一項功能。這段代碼給了我很大的提示。但在實際的實現中,還是遇到一些具體的問題。所以我還是想再談談我的體會。

      通過AppDomain來實現程序集的卸載,這個思路是非常清晰的。由于在程序設計中,非特殊的需要,我們都是運行在同一個應用程序域中。由于程序集的卸載存在上述的缺陷,我們必須要關閉應用程序域,方可卸載已經裝載的程序集。然而主程序域是不能關閉的,因此唯一的辦法就是在主程序域中建立一個子程序域,通過它來專門實現程序集的裝載。一旦要卸載這些程序集,就只需要卸載該子程序域就可以了,它并不影響主程序域的執行。

      不過現在看來,最主要的問題不是子程序域如何創建,關鍵是我們必須實現一種機制,來達到兩個程序域之間完成通訊的功能。如果大家熟悉Remoting,就會想到這個問題不是和Remoting的機制有幾分相似之處嗎?那么答案就可以呼之欲出了,對了,就是使用代理的方法!不過與Remoting不同的是兩個程序域之間的關系。因為子程序域是在主程序域中建立的,因此對該域的控制顯然就與Remoting不相同了。

      我想先用一副圖來表述實現的機制:

      說明:
      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()方法。

      然而在實際的操作過程中,我發現在RemoteLoader類的LoadAssembly方法,是存在遺患的。在我的LoadAssembly方法中,會返回一個Assembly對象。令我百思不得其解的是,雖然都是Assembly對象,但在加載某些程序集并返回Assembly時,在Loader類中會拋出SerializationException異常,并報告反序列化的對象狀態不足。這個異常是在序列化獲反序列化過程中發生的。我反復比較了兩個程序集,一個可以正常加載并序列化,一個會拋出如上異常。會拋出異常的程序集并沒有什么特殊之處,且我在程序中的其他地方也沒有重復加載該程序集。這是一個疑問!!

      不過通常我們在RemoteLoader類中,要實現的方法并非返回一個Assembly對象,而是通過反射加載程序集后,創建該程序集的對象。由于類對象都為object類型,此時序列化就不會出現問題。在我的項目中,因為要獲得程序集的版本號,比較版本號在確定是否需要更新,因此我在RemoteLoader類中,只需要在加載程序集后,返回程序集的版本號字符串類型就可以了。字符串類型是絕對支持序列化的。

      AssemlbyLoader.Dll的源代碼可以點擊這里獲得。在應用程序中,顯示添加對該程序集的引用,然后實例化Loader類對象,來調用該方法即可。我還做了一個簡單的測試程序,用的是LoadAssembly方法。大家可以測試一下,是否如我所說,對于某些程序集,可能會拋出序列化的異常!?

      測試的代碼請點擊這里獲得,測試界面如下:

      同時,大家也可以測試一下,直接加載和通過AppDomain加載,刪除程序集文件時會有什么區別?

      posted @ 2004-09-29 15:21  張逸  閱讀(22779)  評論(37)    收藏  舉報
      主站蜘蛛池模板: 蜜桃视频一区二区三区四| 夜色福利站WWW国产在线视频 | 亚洲国产永久精品成人麻豆| chinese极品人妻videos| 永丰县| 精品粉嫩国产一区二区三区 | 岛国中文字幕一区二区| 柯坪县| 亚洲成人av在线资源网| 精品精品久久宅男的天堂| 午夜在线观看成人av| 国产女主播喷水视频在线观看 | 国产裸体无遮挡免费精品| 亚洲av无码精品色午夜蛋壳| 精品无码一区二区三区水蜜桃| 在线精品国产中文字幕| 亚洲欧美人成人综合在线播放| 黑人精品一区二区三区不| 免费看黄色片| 在线a级毛片无码免费真人| 中文字幕日韩区二区三区| 久久久久影院色老大2020| 99久久99这里只有免费费精品| 亚洲成av人片天堂网无码| 久久亚洲人成网站| 久热这里只有精品在线观看| 国产亚洲精品第一综合另类无码无遮挡又大又爽又黄的视频 | 无码人妻斩一区二区三区| 综合色一色综合久久网| 国产成人亚洲欧美二区综合| 国内少妇偷人精品视频| 激情文学一区二区国产区| 国产福利深夜在线播放| 国产旡码高清一区二区三区| 麻豆国产va免费精品高清在线| 尤溪县| 日韩精品无码去免费专区| 国产av一区二区不卡| 国产午夜亚洲精品国产成人| 广德县| 欧美日韩国产亚洲沙发|