AppDomain与Assembly的动态加载与卸载代码详解


本文摘自PHP中文网,作者黄舟,侵删。

为了将问题描述清楚,我们先来看一个例子。在这个例子中,WinForm上有一个按钮,当用户点击这个按钮后,就会装载一个已经存在的Assembly,并且在界面的Label控件上显示出这个Assembly的FullName。对Reflection稍微熟悉一点的朋友都知道,这是非常简单的事情,只需要用Assembly.LoadFile方法获得Assembly,然后用FullName属性来显示即可,比如下面的代码:

1

2

3

4

5

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。代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

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的卸载。代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

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事件处理过程,改为如下的形式:

1

2

3

4

5

6

7

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的动态加载与卸载代码详解的详细内容!

相关阅读 >>

assembly.reflectiononlyload 方法

assembly.reflectiononlyloadfrom(string) 方法

AppDomain与assembly的动态加载与卸载代码详解

更多相关阅读请进入《AppDomain》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...