.NET面试题系列[2] - .NET框架基础知识(2)
3 程序集
面试出现频率:虽然很重要但不怎么出现,可能会考你定义,以及程序集包括什么,然后自然的话题就跑到反射上去了。
重要程度:8/10,很重要
需要理解的程度:知道程序集包括IL和元数据。知道元数据的作用以及反射的概念。知道GAC是什么。关于反射在后面另有独立章节。对于程序集的强命名,个人认为过于偏僻。
3.1 概念
程序集构成了基于.NET的应用程序的部署、版本控制、重用和安全权限的基本单元。程序集以可执行 (.exe) 文件或动态链接库 (.dll) 文件的形式出现。它们向公共语言运行时提供了解类型实现所需要的信息。可以将程序集看成是构成逻辑功能单元并为一起工作而生成的类型和资源的集合。
如果程序集中含有多个命名空间,则每个命名空间有自己的IL和元数据(即托管模块)。多个托管模块合成一个程序集。CLR是和程序集一起工作的,而不是和托管模块一起。
如果你的程序只是Hello World级的小控制台应用程序,那么编译之后,可能你只会用到.NET最主要的基础类库mscorlib.dll(最重要的程序集之一)。但对于团队级的系统来说,可能会有大量dll文件作为类库。如果你在VS中选择新建一个Class Library,则编译后生成的结果文件是dll文件,没有可执行程序,你也不能在VS中试图运行一个Class Library。
不同程序集中相同的命名空间中相同的成员(例如类型)被认为是不同的。例如My.dll和Your.dll同时在一个命名空间A中定义了一个类B,则它们是不同的。
程序集是自描述的:它的清单部分含有它需要访问的其他程序集(依赖对象)名单,它的元数据包含了程序集中所有类型以及它们的成员。它的IL代码则包括了成员的实现。
程序集是可配置的:可以将其配置到私有或共享(全局程序集缓存,GAC)中。当你在一个类库中引用其他程序集(通过Add References)时,系统将该程序集的dll文件拷贝到你的类库的子目录bin\Debug下(这就是私有配置)。注意Add References不会显示GAC中的程序集。全局的程序集不需要Add References,IDE自动添加。配置到GAC的步骤是一个很偏僻的话题,可参考https://msdn.microsoft.com/zh-cn/library/yf1d93sz.aspx。
3.2 程序集的结构
程序集最重要的两部分是IL和元数据。它们合称托管模块。程序集包括以下部分:
- PE/COFF头:包含了供操作系统查看和利用的信息。Windows操作系统能够加载并运行.dll和.exe是因为它能够理解PE/COFF文件的格式。
- CLR头:告诉操作系统这个PE/COFF文件是一个.NET程序集,区别于其他类型的可执行程序。程序集中包含的IL语言代码并不是计算机可以直接执行的,还需要进行即时编译,那么在对IL语言代码进行编译前,需要先将编译的环境运行起来。
- 清单(manifest):相当于一个目录,描述了程序集本身的信息,例如程序集标识(名称、版本、文化)、程序集包含的资源(Resources)、组成程序集的文件、该程序集需要用到的所有外部程序集名单等。
- 元数据:如果说清单描述了程序集自身的信息,那么元数据则描述了程序集所包含的内容。这些内容包括:程序集包含的模块、类型、类型的成员、类型和类型成员的可见性等。注意,元数据并不包含类型的实现,有点类似于C++中的.h头文件。在.NET中,查看元数据的过程叫做反射(Reflection)。
- IL:也就是元数据中类型的实现,包括方法、属性等。
- 资源文件: 例如图标文件,文本文件,.resx资源文件等。
3.3 元数据的作用
部分元数据的作用:
- IDE通过元数据进行智能感知,例如在你打出一个.之后,自动弹出下拉菜单,获得类型的方法和属性等。
- CLR的代码验证过程使用元数据确保代码只执行类型安全的操作。
- 序列化和反序列化的基础。
- 通过访问元数据来获得类型的成员(即反射)。虽然这会降低性能,但很多时候必须要这么做,例如类型是动态类型,ORM框架即为一个常见的场景。
3.4 程序集和命名空间有何区别?
命名空间是一个程序集内相关类型的一个分组。例如System.IO命名空间包含了有关文件IO的类型。有时,多个程序文件可能共享一个命名空间。例如如果你开发一组几何类圆圈,三角和正方形,你可以将他们的命名空间都设为“Shapes”。
命名空间可以嵌套。例如namespace System.IO等同于
namespace System{
namespace IO{
…
}
}
一个程序集可以包括多个命名空间。在不同程序集中相同名字的命名空间是不同的两个对象。程序集和命名空间的主要区别:
- 程序集是部署,重用应用程序的最小单位,但命名空间不是,它更多的是将具有相似内容的一组类型和方法组织到一起。例如mscorlib.dll中的System命名空间,包含了.NET所有的基元类型。
- 一个程序集可以包括多个命名空间,反之则不行
- Using引用的对象是命名空间,而不能是程序集。你不能using mscorlib.dll。但当你using 例如System.Data(这是一个嵌套的命名空间)时,你可以使用System.Data命名空间的所有可访问类,属性及方法,就像其代码是你的一部分一样。
3.5 什么是GAC?
当你安装了CLR,你就有了一个Global Assembly Cache(全局程序集缓存,GAC)。安装CLR时,系统将把它认为重要的若干程序集放入GAC,例如mscorlib.dll。从 .NET Framework 4 开始,全局程序集缓存的默认位置为 %windir%\Microsoft.NET\assembly。 在 .NET Framework 的早期版本中,默认位置为 %windir%\assembly。
有时候当安装某些应用程序时,也会触发安装程序将程序集放入GAC。
GAC是一个机器级别的程序集,其中包括mscorlib.dll等至关重要的程序集。在Add Reference中,它不会被自动包括进来,必须手动浏览才可以找到部署到GAC中的程序集。如果你打算将类库部署到GAC,一般来说,这个库应当被大量其他工程引用。
不能把可执行的程序集部署到GAC。部署到GAC的细节,参阅精通C#第14章以及https://msdn.microsoft.com/zh-cn/library/yf1d93sz.aspx。在全局程序集缓存中部署的程序集必须具有强名称。将一个程序集添加到全局程序集缓存时,必须对构成该程序集的所有文件执行完整性检查。
4 综合问题
题目:hello world程序。
using System; class Program
{
static void Main(string[] args)
{
string text = "hello, world!";
Console.WriteLine(text);
}
}
问:该程序需要引入什么参考?
答:什么都不需要。
问:也就是说你可以把VS帮你引用的所有参考都删了?
答:是。这个程序只需要基础类库。
问:那你都删了之后,Console类型从哪里来?
答:从mscorlib.dll里来。另外,string这个类型也从那儿来,因为string是基元类型,所有的基元类型都在mscorlib.dll的System命名空间。所以你不能把第一行那个using拿掉。
问:为什么我从来没见过mscorlib.dll?
答:因为它在GAC里,每次自动引用。
问:如果我用VS编程,运行程序(非调试模式),会发生什么?
答:VS会先用C#编译器将源代码编译为一个程序集。程序集包括IL代码。因为源代码没问题,所以编译成功,之后,CLR引用程序集中所有需要的其他程序集(这个例子就是没有其他程序集),进行运行时检查,检查也没问题,就开始调用JIT进行即时编译。将IL转换为机器码。机器运行机器码,打印出hello, world!,然后退出程序。
问:你刚刚提到了程序集,那是作什么用的?
答:程序集是部署和重用应用程序的最小单元。它是自解释的,主要包括IL和元数据,以及资源文件等。
问:你接触过或者对程序集进行过访问吗?
答:在反射时会访问程序集中的元数据。
问:反射有什么用处?它对性能是否有影响?
答:且听以后分解。
5 总结与提高
本部分内容虽然比较抽象,平时也基本不会用到,但作为背景知识,了解一下没有坏处。通过熟悉.NET各个版本的更新,我们可以对.NET框架十余年的发展和它所要达到的目标有一个更加明确的认识。.NET的整个发展就是
- 不断统一:例如WCF统一了Web服务曾经有的各种类型的呼叫方式。LINQ统一了各种资源(XML,各类型数据库)的访问和筛选方式,如果你熟悉表达式树,你甚至可以写一个自己的LINQ TO something。统一的过程就是解放开发者的过程。
- 不断解耦:例如WPF相比Winform,更好的做到了将设计和代码分开,真正让两拨人同时工作。最新的ASP.NET Core彻底和System.Web和IIS解耦。只出现需要的东西,不需要的连影子也不能有。
- 提高代码友好程度:C#中有数不胜数的例子,随便举几个:C# 6的$符号,async和await关键字(异步的巅峰),以及那越来越像函数式编程,无处不在的lambda表达式。代码的可读性越来越强,甚至完全不懂编程的人,只要他认识英语,就能看懂大概。
几条主要脉络:
- Web服务:RPC以及其他 -> WCF (SOAP) -> Web API (REST) -> Web API 2 (REST)
- Web应用: ASP -> ASP.NET -> ASP.NET MVC -> ASP.NET Core
- 数据库:ADO.NET -> ADO.NET Entity Framework (ORM)
- 异步编程:委托 -> 事件 -> 任务 -> 任务语法糖
而未来则是函数式编程的世界,Web App的世界,开源的世界,依赖注入的世界,以及nuget的世界。通过学习.NET的演化史,我认为这个平台的未来是光明的。熟悉.NET的历史,你可以令人信服的证明你对.NET充满兴趣,在和面试官闲聊时,也是不错的谈资,特别是面试官本人也是技术大牛时,他可能会觉得你是个可造之材。如果你资历深厚,甚至了解.NET出现之前业界的状况,那么你对.NET对整个开发产业的改变一定有着比我深入更多的认识,甚至你可以猜测.NET将来的发展方向。
对于程序集这部分,实际上还是有比较多机会接触到的,了解程序集对后面反射,动态类型和晚期绑定等很多内容的学习大有帮助。
书籍推荐:CLR via C#第一部分
.NET面试题系列[2] - .NET框架基础知识(2)的更多相关文章
- .NET面试题系列[1] - .NET框架基础知识(1)
很明显,CLS是CTS的一个子集,而且是最小的子集. - 张子阳 .NET框架基础知识(1) 参考资料: http://www.tracefact.net/CLR-and-Framework/DotN ...
- 【Java面试题系列】:Java基础知识常见面试题汇总 第一篇
文中面试题从茫茫网海中精心筛选,如有错误,欢迎指正! 1.前言 参加过社招的同学都了解,进入一家公司面试开发岗位时,填写完个人信息后,一般都会让先做一份笔试题,然后公司会根据笔试题的回答结果,确定 ...
- 【Java面试题系列】:Java基础知识常见面试题汇总 第二篇
文中面试题从茫茫网海中精心筛选,如有错误,欢迎指正! 第一篇链接:[Java面试题系列]:Java基础知识常见面试题汇总 第一篇 1.JDK,JRE,JVM三者之间的联系和区别 你是否考虑过我们写的x ...
- 【Xamarin开发 Android 系列 4】 Android 基础知识
原文:[Xamarin开发 Android 系列 4] Android 基础知识 什么是Android? Android一词的本义指“机器人”,同时也是Google于2007年11月5日宣布的基于Li ...
- MySQL系列(一)--基础知识大总结
MySQL系列(一)---基础知识大总结 前言:本文主要为mysql基础知识的大总结,mysql的基础知识很多,这里只是作为简单的介绍,但是具体的细节还是需要自行搜索.当然本文还有很多遗漏的地方,后续 ...
- PHP面试(二):程序设计、框架基础知识、算法与数据结构、高并发解决方案类
一.程序设计 1.设计功能系统——数据表设计.数据表创建语句.连接数据库的方式.编码能力 二.框架基础知识 1.MVC框架基本原理——原理.常见框架.单一入口的工作原理.模板引擎的理解 2.常见框架的 ...
- DDD框架基础知识
DDD框架基础知识 参考: https://www.cnblogs.com/zhili/p/OnlineStorewithDDD.html(领域驱动设计,分层架构) https://www.cnblo ...
- 4-1 Spring框架基础知识
Spring框架基础知识 1.Spring 框架作用 主要解决了创建对象和管理对象的问题. 自动装配机制 2.Spring 框架 (Spring容器,JavaBean容器,Bean容器,Spring容 ...
- iOS开发系列--C语言之基础知识
概览 当前移动开发的趋势已经势不可挡,这个系列希望浅谈一下个人对IOS开发的一些见解,这个IOS系列计划从几个角度去说IOS开发: C语言 OC基础 IOS开发(iphone/ipad) Swift ...
随机推荐
- 在Ubuntu下搭建ASP.NET 5开发环境
在Ubuntu下搭建ASP.NET 5开发环境 0x00 写在前面的废话 年底这段时间实在太忙了,各种事情都凑在这个时候,没时间去学习自己感兴趣的东西,所以博客也好就没写了.最近工作上有个小功能要做成 ...
- 探索ASP.NET MVC5系列之~~~3.视图篇(下)---包含常用表单和暴力解猜防御
其实任何资料里面的任何知识点都无所谓,都是不重要的,重要的是学习方法,自行摸索的过程(不妥之处欢迎指正) 汇总:http://www.cnblogs.com/dunitian/p/4822808.ht ...
- 快速搭建springmvc+spring data jpa工程
一.前言 这里简单讲述一下如何快速使用springmvc和spring data jpa搭建后台开发工程,并提供了一个简单的demo作为参考. 二.创建maven工程 http://www.cnblo ...
- c#多线程
一.使用线程的理由 1.可以使用线程将代码同其他代码隔离,提高应用程序的可靠性. 2.可以使用线程来简化编码. 3.可以使用线程来实现并发执行. 二.基本知识 1.进程与线程:进程作为操作系统执行程序 ...
- 来吧,HTML5之基础标签(上)
什么是html5 HTML 5 是下一代的 HTML.HTML5 仍处于完善之中.然而,大部分现代浏览器已经具备了某些 HTML5 支持. 学习过程中标签的理解 <a>标签 定义超链接, ...
- C# await和async
基础阅读:http://www.cnblogs.com/jesse2013/p/async-and-await.html 答疑阅读:http://www.cnblogs.com/heyuquan/ar ...
- Newtonsoft.Json设置类的属性不序列化
参考页面: http://www.yuanjiaocheng.net/webapi/parameter-binding.html http://www.yuanjiaocheng.net/webapi ...
- prometheus监控系统
关于Prometheus Prometheus是一套开源的监控系统,它将所有信息都存储为时间序列数据:因此实现一种Profiling监控方式,实时分析系统运行的状态.执行时间.调用次数等,以找到系统的 ...
- Android Retrofit 2.0 使用-补充篇
推荐阅读,猛戳: 1.Android MVP 实例 2.Android Retrofit 2.0使用 3.RxJava 4.RxBus 5.Android MVP+Retrofit+RxJava实践小 ...
- 为什么 Android Studio 工程文件夹占用空间这么大?我们来给它减减肥
偶然中发现Android Studio的工程文件夹比ADT Bundle的大很多.用Android Studio新建一个空工程,工程文件夹大小为30M,运行一次后大小为40M.同样用ADT Bundl ...