《.NET程序员面试秘笈》----面试题14 简述程序集和应用程序域-阿里云开发者社区

开发者社区> 开发与运维> 正文

《.NET程序员面试秘笈》----面试题14 简述程序集和应用程序域

简介: 【考点】.NET程序集的知识,.NET应用程序域的理解,.NET应用程序域与程序集的简单应用

本节书摘来自异步社区《.NET程序员面试秘笈》一书中的第1章,面试题14,作者: 张云翯, 更多章节内容可以访问云栖社区“异步社区”公众号查看。

面试题14 简述程序集和应用程序域

.NET程序员面试秘笈
【考点】.NET程序集的知识,.NET应用程序域的理解,.NET应用程序域与程序集的简单应用。

【出现频率】

【解答】

.NET的程序集用于解决DLL HELL,DLL HELL是指与DLL有关的问题。程序集是自我描述的安装单元,这是一个逻辑单元,而非一个文件。程序集可以是包含元数据的多个文件,也可以是一个DLL或EXE文件。简而言之,程序集是作为整体发布的.NET可执行程序或.NET可执行程序的一部分,包含了程序的文件集或资源文件。

程序集分为私有程序集和共享程序集,私有程序集是创建.NET项目时默认的,也是比较常用的方式。私有程序集以可执行文件或库的形式提供应用程序,库中的代码只服务于这个应用程序。而共享程序集是一个公共库,可服务于系统中所有程序。共享程序集必须安装到.NET的特别目录中,而其他被服务的程序则不需要知道安装的地方。

【分析】

任何.NET程序均由程序集构成,程序集是包含已编译的、面向.NET Framework的代码的逻辑单元。当程序集存储于多个文件当中时,则一定有一个主文件包含程序集主程序的入口,这个包含入口的主文件描述了位于相同程序集的其他文件。程序集包含描述自身的元数据,这种元数据位于程序集清单中,可用于检查版本以及自身的完整性。

说明:

动态程序集位于内存中,而非存储于文件中。
应用程序域是.NET中的程序的“边界”。相对于进程边界,应用程序域边界范围更小。在Windows 7/XP中,进程可以有效保证不同的程序安全地运行,当某个程序出错时并不会影响其他程序。但是进程对多程序运行的系统性能作出了妥协,因为进程之间不允许共享内存。可以使用基于DLL的组件解决这个问题,将所有的DLL组件在一个地址空间中运行,不过当某个组件出错时将会影响其他组件。使用应用程序域可以分离组件,并且不会导致类似于进程的性能问题。

说明:

进程有独立的虚拟内存,以保证进程之间的内存无法互写。
在一个进程内可容纳多个应用程序域,这样,.NET中的应用程序域可使多个应用程序运行于同一个进程。在没有代理的情况下,不同的应用程序域中的实例和静态成员无法共享,这样也保证了安全性。

说明:

程序集的代码只需加载一次,以减少内存消耗。
本例展示了程序集和应用程序域的简单应用。在VS环境(VS2008或VS2010)中创建一个新控制台应用程序,名称为AppA,在Program.cs中编写代码如程序1.16所示。

程序1.16 AppA项目:Program.cs

  using System;
  using System.Collections.Generic;
  using System.Text;
  namespace AppDomainTest
  {
    class Program
    {
      static void Main(string[] args)
      {
        //创建AppDomain类型的current,用于引用AppDomain.CurrentDomain
        AppDomain current = AppDomain.CurrentDomain;
        //输出程序的应用程序域的名称
        Console.WriteLine("大家好,我是程序集AppA,我所在的应用程序域是{0}。", current.FriendlyName);
      }
    }
  }

执行本程序,可得到结果如图1.22所示。


e97b208f5898591f2954b4e801e55a95a0445156

可见,当应用程序运行时,默认所在的应用程序域的名称为程序名称。现在AppA项目已经编译了最简单的私有程序集,位于ch01AppAAppAbinDebug目录下。接下来用同样的方法在VS环境中创建新项目,名称为AppB,在其Program.cs中编写代码如程序1.17所示。

程序1.17 AppB项目:Program.cs

  using System;
  using System.Collections.Generic;
  using System.Text;
  namespace AppDomainTest
  {
    class Program
    {
      static void Main(string[] args)
      {
        //创建AppDomain类型的one,用于引用AppDomain.CurrentDomain
        AppDomain one = AppDomain.CurrentDomain;
        //输出one的基目录以及名称、上下文信息
        Console.WriteLine("大家好,我是程序集B,我的基目录:{0}\n我所在的应用程序域的名称及上下文策略:{1}", one.BaseDirectory, one.ToString());
        //在当前的应用程序域中加载程序集AppA.exe
        one.ExecuteAssembly("AppA.exe");
        Console.WriteLine("\n上面的AppA程序集和下面的AppA程序集位于不同的应用程序域\n");
        //创建AppDomain类型的tow,用于引用AppDomain类创建的新应用程序域,其名称为ROOM-A
        AppDomain two = AppDomain.CreateDomain("ROOM-A");   
        //two应用程序域装载(执行)AppA.exe程序集
        two.ExecuteAssembly("AppA.exe");
        //输出two的基目录以及名称、上下文信息
        Console.WriteLine("AppA程序集的基目录:{0}\nAppA程序集所在的应用程序域的名称及上下文策略:{1}", two.BaseDirectory, two.ToString());
      }
    }
  }

执行程序前,首先需添加程序集引用,在VS中的菜单栏中单击“项目|添加引用”,在添加引用的对话框中单击“浏览”选项,如图1.23所示。

浏览AppA项目的程序集路径,即ch01AppAAppAbinDebug目录,选中AppA.exe,单击“确定”按钮即可。这步的操作实际上把AppA程序集直接复制到AppB项目程序集的相同目录下,即复制到ch01AppBAppBbinDebug目录下。这也充分展示了私有程序集安装的便捷性,现在,AppB应用程序执行时即可将AppA程序集装载到新建的应用程序域了。执行AppB项目的程序,可得到结果如图1.24所示。


c3c2bda07c50e7c8fd738e97d838557a591da258

如图所示,AppA程序集首先被加载到当前应用程序域,然后被加载到名称为“ROOM-A”的应用程序域中。从任务管理器中观察,AppA程序集并没有创建新的进程。AppB程序集所在的应用程序域被称为进程中的主应用程序域,这是运行时自动创建的。

说明:

实际上AppA程序集已加载到AppB.exe进程中运行,这就达到了多个应用程序在同一个进程中运行的目的。
本节问题相对比较靠近.NET的底层,编程者必须理解程序基本的运行过程,才能写出更高效的程序。从本节的代码中可知,AppDomain类用于创建和中断应用程序域,加载和卸载程序集合类等功能,另外AppDomain类还可以枚举应用程序域中的程序集和线程。由于程序集包含了元数据,其中含有所有定义的类型以及这些类型成员的细节,所以可通过反射技术来获取这些数据。

本节示例主要展示了应用程序域的简单使用,其“边界”作用不同于进程,不同应用程序域中的应用程序有自己独立的内存空间。在默认情况下,这些程序互相隔离,保证程序安全运行。示例中AppB.exe程序运行情况如图1.25所示。


895b06d5282875e496edbda0839c2462fd9556bb

本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章