AppDomain與Assembly的動態載入與解除安裝程式碼詳解

黄舟
發布: 2017-03-15 11:02:12
原創
3641 人瀏覽過

為了將問題描述清楚,我們先來看一個例子。在這個範例中,WinForm上有一個按鈕,當使用者點擊這個按鈕後,就會裝載一個已經存在的Assembly,並且在介面的Label 上顯示出這個Assembly的FullName。對Reflection稍微熟悉一點的朋友都知道,這是非常簡單的事情,只需要用Assembly.LoadFile方法獲得Assembly,然後用FullName屬性來顯示即可,例如下面的程式碼:

private void button1_Click(object sender, EventArgs e)  
{  
    Assembly assembly = Assembly.LoadFile(@"C:\testlib.dll");  
    label1.Text = assembly.FullName;  
}
登入後複製



#當然,程式執行正常,您不會發現任何編譯時或執行時的錯誤。然而,當你在沒有退出此程式之前,再去編譯被呼叫的testlib.dll,你會發現,Visual Studio無法完成編譯,提示說該檔案正在被其它的進程所使用。

事實上,我們的程式與這個testlib.dll並沒有太大的關聯,我們的程式只不過就是顯示一下testlib.dll的基本資訊。如果testlib.dll是一個共享的函式庫,那麼資源獨佔問題會影響到其它程式的正常運作。

Assembly沒有Unload的功能,但可以使用AppDomain來解決這個問題。基本想法是,建立一個新的AppDomain,在這個新建的AppDomain中裝載assembly,呼叫其中的方法,然後將獲得的結果回傳。在完成所有操作以後,呼叫AppDomain.Unload方法卸載這個新建的AppDomain,這樣也同時卸載了assembly。注意:你無法將裝載的assembly直接返回到目前應用程式網域(AppDomain)。

首先,建立一個RemoteLoader,這個RemoteLoader用於在新建的AppDomain中裝載assembly,並向外公佈一個屬性,以便外界能夠獲得assembly的FullName。 RemoteLoader需要繼承於MarshalByRefObject。程式碼如下:

public class RemoteLoader : MarshalByRefObject  
{  
    private Assembly assembly;  
    public void LoadAssembly(string fullName)  
    {  
        assembly = Assembly.LoadFrom(fullName);  
    }  
    public string FullName  
    {  
        get { return assembly.FullName; }  
    }  
}
登入後複製



#其次,建立一個LocalLoader。 LocalLoader的功能是建立新的AppDomain,然後在這個新的AppDomain中呼叫RemoteLoader,以便透過RemoteLoader來建立assembly並取得assembly的相關資訊。此時被呼叫的assembly自然被裝載在新的AppDomain中。最後,LocalLoader還需要提供一個新的方法,就是AppDomain的卸載。程式碼如下:

public class LocalLoader  
{  
    private AppDomain appDomain;  
    private RemoteLoader remoteLoader;  
    public LocalLoader()  
    {  
        AppDomainSetup setup = new AppDomainSetup();  
        setup.ApplicationName = "Test";  
        setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;  
        setup.PrivateBinPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "private");  
        setup.CachePath = setup.ApplicationBase;  
        setup.ShadowCopyFiles = "true";  
        setup.ShadowCopyDirectories = setup.ApplicationBase;  
        appDomain = AppDomain.CreateDomain("TestDomain", null, setup);  
        string name = Assembly.GetExecutingAssembly().GetName().FullName;  
        remoteLoader = (RemoteLoader)appDomain.CreateInstanceAndUnwrap(  
            name,  
            typeof(RemoteLoader).FullName);  
    }  
    public void LoadAssembly(string fullName)  
    {  
        remoteLoader.LoadAssembly(fullName);  
    }  
    public void Unload()  
    {  
        AppDomain.Unload(appDomain);  
        appDomain = null;  
    }  
    public string FullName  
    {  
        get  
        {  
            return remoteLoader.FullName;  
        }  
    }  
}
登入後複製


  • 最後,修改我們WinForm上的Button Click事件處理過程,改為如下的形式:

private void button1_Click(object sender, EventArgs e)  
{  
    LocalLoader ll = new LocalLoader();  
    ll.LoadAssembly(@"C:\testlib.dll");  
    label1.Text = ll.FullName;  
    ll.Unload();  
}
登入後複製



在完成上述的修改後,我們的程式也同樣能夠正確地顯示assembly的FullName,而且,在顯示完assembly資訊後,程式會主動卸載新建的AppDomain,以防止testlib.dll的資源獨佔,影響其它程式的運行。

 

 

以上是AppDomain與Assembly的動態載入與解除安裝程式碼詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板