《Essential .Net》读书笔记 - Chapter 2

** Chapter 2

**

1. CLR 程序存在于模块中( module )中。一个 CLR 模块是一个字节流,储存在一个文件(本地或远程服务器)。

2. CLR 模块采用 WinNT 的 PE(Portable Executable)/COFF(Common Object File Format) 格式的 扩展版 。 CLR 模块也是有效的 Win32 模块,可以通过 LoadLibrary 系统调用加载。 CLR 模块用到的 PE/COFF 的功能极少,大部分内容是使用 PE/COFF 文件的 .text 部分。

3. CLR 模块包括 代码元数据资源 。代码使用 CIL(Common Intermediate Language) 格式存放(个人理解:这个和 MSIL 或者 IL 是一个东西)。模块的元数据描述了模块中定义的类型,包含名字、继承关系、方法签名和依赖关系等。模块的资源由静态的只读数据组成(字符串、位图等)。

4. ( /t:exe 、 /t:winexe 、 /t:library 、 /t:module ) module 产生的是“未加工”的模块( .netmodule )。 /t:library 编译产生的模块( .dll )包含元数据。 /t:exe 生成控制台程序、 /t:winexe 产生 Win 程序。

5. 起点为四种形式之一: static void Main(){} 、 static void Main(string[] argv){} 、 static void Main(){return 0} 、 static void Main(string[] argv){return 0} 。是否有 public 无所谓,一个程序不可有多个入口,多个 Main 函数需要在编译时使用 /main 开关。

6. 程序集( assembly )为一个或多个模块的逻辑集合。程序集通过独立于位置的名字进行引用。这个名字必须翻译为文件系统中或 Internet 上的物理路径,最终指向一个或多个包含类型定义、代码以及资源的模块。

7. “多模块”的作用就是把“常用”和“不常用”的代码加载区分开来(可以在运行时做到“要什么下载什么”),可以作到使用一种语言写底层,一种语言写界面。

8. 一个模块往往只属于一个程序集,如果需要违反,那么会将这个公用模块产生两个不用的拷贝。

9. 模块依赖于来自其他程序集的类型(至少有 mscorlib.dll 里的),每个模块都有一个程序集名字列表,然后 CLR 负责在运行时将这些程序集的名字转换成模块的路径名。

10. 每个程序集有一个程序集清单( assembly manifest ),这是元数据的一部分,相当于附加类型定义和代码的附属文件目录。

11. 含有程序集清单的模块首先被 CLR 加载,然后根据这个清单的内容加载其余不含清单的模块。

12. 引用别的模块使用 ** /addmodule ** 开关,引用别的程序集使用 ** /r ** 开关。

13. 含有程序集清单的模块将包含外部引用程序集的主要列表。列表由程序集中每个模块的依赖关系组成,这样通过加载一个文件就能找到程序集所有的依赖关系。

14. ** internal ** 导致只对 同一程序集的模块 可用; ** public ** 导致 所有的代码 都可用; ** private ** 只有 该类型的方法 才可用; ** protected ** 使 派生类的方法等也能 访问该成员; ** protected ** 和 ** internal ** 可以一起用。

15. 命名空间( namespace ) + 类名。

16. 每个程序集采用四部分( four-part )名字,作为唯一的标识。这四部分为 名称、文化、开发人员、组件版本 。这些名字被放在程序集清单里,在加载时, CLR 使用四部程序集名字找到正确的组件。

17. 每个程序集的名字都有一个版本号: Major.Minor.Build.Revision ,如果没有显式设定这个版本号,那么就是 0.0.0 .0 。 System.Reflection.AssemblyVersion 能接受各种字符串格式( 1.2.d.s 等)。

18. CultureInfo 特性标识着组件开发所用到的语言和国家代码(语言环境)。含有 CultureInfo 特性的程序集不能包括代码,必须是“纯资源”的程序集( resource-only )。含代码的程序集是文化无关的( culture-neutral )。

19. 程序集名字包含一个“公钥” (public key) ,标识组件的开发人员。可以选择使用 8 位的或者 128 位的公钥标记,这样就可以标记着相同文件名的不同程序集。

20. 有时候必须手动引用程序集。 CLR 定义了一个标准格式,用于将程序集的四部分名字编写字符串。这个格式被称为程序集的显示名字( display name ): Name, Virsion=X.X.X.X, Culture=[xx-XX | Neutral], PublicKeyToken=[XXXXXXXXXXXXX | Null] 。 Culture 为 Neutral 表示程序集没有文化限制, PublicKeyToken 为 null 表示不带公钥。简单省略一个部分的限定名字表示允许匹配任何 Culture 或 PublicKeyToken 。

21. 一般来说,应该避免使用程序集的部分限定名,否则 CLR 可能会以非预期的方式运行。可以在配置文件里写全名,然后使用部分名在程序中调用( Assembly assm = Assembly.Load(“XXXX”) )。 PartialName (上面的 XXXX )必须存在于配置文件的 PartialName 中

22. CLR 会尽量少加载不需要的模块,当确实使用了才会加载。这样减少了初始化时间,也减少了运行程序所消耗的资源。 CLR 加载是由基于类型的 JIT 编译器触发的, JIT 将方法体的 CIL 编译成机器码时,要访问的局部变量,参数等数据类型会被一起加载。

23. 如果不要 CLR 屡次的加载模块可以有两种做法:一是定义一些静态字段。二是用手动显式加载。

24. 如果要显式的和程序集交互,需要使用 System.Reflection.Assembly 的 LoadFrom 方法,它可以是本地的一个文件,也可以是“ file://... ”,如果是从非“ file://... ”的 URL 中调用,则需要 Web Permission ,这个模块被加载时会被首先下载到缓存里。

25. 尽管通过位置加载程序集很有意思,但是大多数程序集是通过程序集解析器( assembly resolver )按名字加载的。方法是 System.Reflection.Assembly 的 Load 方法,涉及到所在目录,版本控制和一些其他配置细节的问题。

26. 程序集解析器首先采用的是有效的 版本策略 ( version policy ),然后可能会加载所需程序集的替代版本(不同版本的程序集为不同程序集,但是程序集映射的时候必须同名)。版本策略只能应用于四部分名完全限定的程序集,如果程序集名字是部分限定的(比如缺少公钥标记,版本或文化)那么就不能用版本策略了(直接使用 LoadFrom 方法由于指定的是文件,所以就没有什么版本策略的问题了)。

27. 版本策略可以通过配置文件决定,计算机范围( machine-wide )的配置文件为 machine.config ,存在于 %SystemRoot%\Microsoft.net\Framework\V1.0.nnnn\CONFIG 目录下。对于应用程序范围( application-wide )的配置文件,普通应用程序是应用程序目录下,文件名为 EXE 文件名后加 config 扩展名。 ASP.NET 为 web.config 。

28. 配置文件为 XML 语言文件,总有一个 configuration 的根元素。这些配置文件的设置控制了探测路径以及发行者版本策略模式。此外, dependentAssembly 元素被用于对每个依赖的程序集制定版本和定位设置。(配置文件在 中文版 ** P36 ** ** 页 ** 有范例)。

29. 版本策略在三个级别上指定:应用程序( per application ) à 组件( per component ) à 机器( per machine )。前者输出为后者的输入。

30. 除了特定应用程序和计算机范围的配置文件外,给定的程序集还有 发行者策略 ( publisher policy )。它由开发人员声明,标明哪些版本是互相兼容的。

31. ** 中文版 ** ** P39 ** ** 页 ** ——展示了程序集解析器寻找适合的程序集文件的整个过程。

32. 为了避免二义性,程序集解析器只有在被请求的程序集名字中包含公钥时才查找 GAC 。公钥既能够作为程序集引用或者 Assembly.Load 参数的一部分显式地被提供,也可以通过 qualityAssembly 配置文件隐式地被提供。

33. GAC 由系统级的组件( FUSION.DLL )控制,将 DLL 缓存存储在 %WINNT%\Assembly 目录下。

34. CODEBASE 提示配置文件实例: 中文版 ** P41 ** ** 页 **

35. 如果程序集解析器通过 GAC 或 CODEBASE 提示都无法定位程序集,那么程序集解析器将对于应用程序根目录相关的目录进行查找。这个查找被称为 探测 ( probing )。( 中文书 ** P43 - P45 ** ** 页 ** )

36. 程序集被版本化为一个单元。如果替换程序集中文件的一个子集,而不更新版本号,将导致不可预测的结果。如果类型的功用约定改变了,类型的程序集必须赋予一个新的版本号。

37. CODEBASE 提示,私有探测路径以及 GAC 就可以支持多个版本的并行安装,这允许给定的程序集的多个版本在文件系统中和平共处。然而,如果有多个这样的程序集被独立程序或者单个程序实际加载到内存中,那么,事情在某种程度上就是不可预测的。并行执行要比并行安装要难处理得多。

38. 共享类型需要被部署到单独的程序集中,它本身不会被版本化。(和《 Applied 》中描述接口应用程序的说法比较类似)。

39. 用于程序集的原数据具有三个特别的特性,他们允许开发人员制定程序集的版本是否同时能被加载。这些元数据为都被现行的程序集解析器和加载器所忽略。然而,他们确实能够起到提示作用,这个提示有望在 CLR 的未来版本中实施。

Published At
Categories with Web编程
Tagged with
comments powered by Disqus