01

程序集

程序集是包含编译好的、基于.Net Framework的代码逻辑单元。一般来说,在Visual Studio中的一个项目即一个程序集,而一个项目中包含多种不同的代码文件。程序集分为可执行程序集和库程序集,比如一个Winform项目就编译为可执行程序集,而Winform项目所包含的其他库项目则编译为库程序集。可执行程序集包含主程序入口点,而库程序集不包含。

程序集的特点是,它是完全自描述的,这和传统的COM组件非常不同,而自描述的程序集正是要解决传统COM组件的信息分离问题。一个COM组件,往往包含了库文件(dll、ocx等文件),同时COM需要注册到注册表生成GUID以供调用,这便对操作系统有了强依赖,有些情况下还需要读取类型库(lib文件),这样一来一个COM组件被分离成三部分,一致性就存在很大的问题。而程序集自描述的“元数据”存储了程序集本身以及程序集所依赖的库文件的信息,从而能够对一致性进行检查而避免了因为运行了不一致的程序集而导致运行中发生错误。对于程序集的一个应用案例就是,我之前用其他更古老的语言开发时,要做自动升级功能时,只能简单的以文件修改日期的新旧来判断是否应该更新,而类库之间相互依赖关系,那根本就无法知道了,除非发布应用自带一个独立的配置文件来描述这些关系。而对于.Net来说,有了程序集,配置是自带在代码里的,就可以做到非常精细化的升级控制,从而保证程序的正确和安全的更新。

程序集分为私有程序集和共享程序集。

私有程序集可以理解为“拷贝即可执行的绿色程序包”,它不依赖于注册表,程序集只要位于主执行程序的所在目录或子目录下,即可正确运行。
共享程序集当然是为了“共享”。比如一个公司发布了多个产品,它们依赖于相同的底层类库,公司发布它的产品时,不想每个产品都发布一份底层类库的拷贝,那可能导致不同拷贝间的不一致以及安装包比较庞大,此时就适合使用共享程序集。当然为了实现共享,程序集就需要放在操作系统的公共空间中(全局程序集缓存GAC),这就可能导致不同公司程序集的名称冲突,因此.Net提供了私钥加密法为共享程序集生成一个能保证唯一性的名称(强名strong name)。

因为程序集中包含了描述自身的元数据,所以可以编程访问这些元数据,这个技术称为“反射”。使用反射可实现业务逻辑的“解耦”,是个比较常用的代码优化手段。但反射也不应该过度使用,我的系统里很少反射,因为必须用反射的地方其实很少。我的编程观念是:业务逻辑应该首选使用“代码”来描述,而不是配置文件,这样形成的代码,是非常清晰容易阅读、理解和维护的。我非常讨厌Java界的那种想用配置描述一切的思路。

02

.Net Framework类

.Net的强大功能,给程序员带来的最大的感受可能是来自于.Net Framework类库。.Net类库非常全面,其实学习.Net,很大的部分就是学习.Net类库。

这里补充下我对.Net类库的使用感受。按照我自己的使用习惯,我自己为项目创建的自有类库非常“瘦”,即非常简单。而我非常不赞赏的是,看到很多初学者,也包括一些.Net高手,都喜欢在.Net类库之上再搞一层自己的“类库”,翻开其代码看看,大部分是将.Net类库的一部分抽取出来,简单封装一下自己用,这个封装可能就是一个两三行代码的方法,就这样封装出大量的类库和方法。其目的很明显:我觉得这个是常用的功能,所以封装一下,以后用它就比较方便。这在Java,C#之前的编程时代,可能是正确的,因为那时候没有这么全面而强大的类库,但对于.Net的使用,我是拒绝这么做的,理由如下:

1)版本的阉割:.Net类库非常广泛,而封装自己的类库是个阉割版本,功能大大弱化。

2)思想的禁锢:有人说,我可以在合适的场景使用我的类库,当我的类库实现不了时,就去找.Net类库的方法。但我可以明确的说,实际操作中这很难做到,原因就是:人的路径依赖。当你长年累月的使用自己的类库后,你必然大概率会忘记.Net类库还有更好的实现方法,而倾向于自己去封装新的方法。这就把自己禁锢在自己的一亩三分地里,8年10年后,你大概率对.Net类库还是不生疏的,只是掌握了一些简单的功能。

而就算你真的每次都记得去.Net类库找方法,长期下来很多场景被应用后,当你自己的类库已经封装了.Net类库10个方法中的9个,那你这样的“二传手”封装并没有起到简化开发的作用,意义又在哪里?

3)代码复杂化:在你的编程思想被禁锢后,代码复杂化随之而来。.Net类库有非常丰富的“重载”方法,即一个对象的方法,针对不同的应用场景会有多达十几种封装方法,在不同的应用场景使用合适的方法,可以写出非常简洁优美的代码。而自己封装的类库,往往只能封装其中的一两种重载方法,结果是,在一种场景中写代码是方便了,而在所有其他场景中写代码又必须自己写补充代码来达到和.Net重载方法同样的功能,代码反而变得臃肿。

所以,我的方法是,在问题的源头上,就避免思想被禁锢的可能,即原则上不封装自己的类库,除非.Net类库就是没相关实现。抱着开放的态度,有问题随时在.Net类库中寻找方法。而我确实发现,即使当解决方案规模达到了近百项目,可能用到的自封装类库也不超过几个封装类以及其中的20个方法。

一个有趣的事实是,.Net类库的大部分,都是使用C#编写的。

03

名称空间

名称空间是避免.Net类名冲突的方式。名称空间是可以嵌套的,比如System空间下包含子空间System.Array。

第一章讲解完毕,下回我们开始讲解第二章:核心C#。

曾经觉得元数据很玄乎,现在看看其实没什么,即基础描述性数据,数据的数据。附篇2篇文章可了解一下元数据。

觉得文章有意义的话,请动动手指,分享给朋友一起来共同学习进步。

欢迎关注本人微信公众号,更及时的关注最新文章(每周三篇原创文章,以及多篇专题文章):

附文:

李建忠:Metadata是.NET平台的核心灵魂

C# 元数据描述

上一篇:解读经典-《C#高级编程》第七版-Chapter1-.Net体系结构-Page6-13

解读经典-《C#高级编程》第七版-Chapter1-.Net体系结构-Page13-20的更多相关文章

  1. c#高级编程第七版 学习笔记 第一章 .NET体系结构

    第一章      .NET体系结构 本章内容: 编译和运行面向.NET的代码 Microsoft中间语言(Microsoft Intermediate Language,MSIL或简称IL)的优点 值 ...

  2. c#高级编程第七版 学习笔记 第二章 核心c#

    第二章 核心C# 本章内容: 声明变量 变量的初始化和作用域 C#的预定义数据类型 在c#程序中使用条件语句.循环和跳转语句执行流 枚举 名称空间 Main()方法 基本的命令行c#编译器选项 使用S ...

  3. c#高级编程第七版 学习笔记 第三章 对象和类型

    第三章 对象和类型 本章的内容: 类和结构的区别 类成员 按值和按引用传送参数 方法重载 构造函数和静态构造函数 只读字段 部分类 静态类 Object类,其他类型都从该类派生而来 3.1 类和结构 ...

  4. ASP.NET MVC 4高级编程(第4版)

    <ASP.NET MVC 4高级编程(第4版)> 基本信息 作者: (美)Jon Galloway    Phil Haack    Brad Wilson    K. Scott All ...

  5. 《UNIX环境高级编程(第3版)》

    <UNIX环境高级编程(第3版)> 基本信息 原书名:Advanced Programming in the UNIX Environment (3rd Edition) (Addison ...

  6. 【转】apue《UNIX环境高级编程第三版》第一章答案详解

    原文网址:http://blog.csdn.net/hubbybob1/article/details/40859835 大家好,从这周开始学习apue<UNIX环境高级编程第三版>,在此 ...

  7. Linux - Unix环境高级编程(第三版) 代码编译

    Unix环境高级编程(第三版) 代码编译 本文地址:http://blog.csdn.net/caroline_wendy 时间:2014.10.2 1. 下载代码:http://www.apuebo ...

  8. Unix环境高级编程第三版中实例代码如何在自己的linux上运行的问题

    学习Linux已经有2个月了,最近被期末考试把进度耽误了,前几天把Unix环境高级编程看了两章,感觉对Linux的整体有了一些思路,今天尝试着对第一章涉及到的一个简单的交互式shell编译运行一下,结 ...

  9. C#高级编程 (第六版) 学习 第七章:委托和事件

    第七章 委托和事件 回调(callback)函数是Windows编程的一个重要方面,实际上是方法调用的指针,也称为函数指针. .Net以委托的形式实现了函数指针的概念,.Net的委托是类型安全的. 委 ...

  10. C#高级编程第11版 - 第七章 索引

    [1]7.1 相同类型的多个对象 1.假如你需要处理同一类型的多个对象,你可以使用集合或者数组. 2.如果你想使用不同类型的不同对象,你最好将它们组合成class.struct或者元组. [2]7.2 ...

随机推荐

  1. ABAP 常见系统表

    TRDIRT Program nameTFTIT Function module nameDD02T Table name

  2. spring扩展点总结

    NamespaceHandler 通过自定义的NamespaceHandler,配合BeanDefinitionParser,可以完成自定义Bean的组装操作,对于BeanDefinition的数据结 ...

  3. PHP引用(&)练习

    <?php class talker { private $data = 'Hi'; public function & get(){ //返回值指向一个内容,这里是指向$data的内容 ...

  4. POI对Excel的操作

    1. 先导包 commons-io-2.6.jar包,用于对文件的操作. 下载地址:http://commons.apache.org/proper/commons-io/download_io.cg ...

  5. JAVA:调用cmd指令(支持多次手工输入)

    JDK开发环境:1.8 package com.le.tool; import java.io.BufferedReader; import java.io.File; import java.io. ...

  6. 【Solidity】学习(2)

    address 地址类型 40个16进制数,160位 地址包括合约地址和账户地址 payable 合约充值 balance,指的是当前地址的账户value,单位是wei this指的是当前合约的地址 ...

  7. [转] OpenStack — nova image-create, under the hood

    I was trying to understand what kind of image nova image-create creates. It's not entirely obvious f ...

  8. Docker学习笔记-Redis 安装

    拉取官方的镜像 docker pull redis:3.2 查看 docker images redis 运行容器 docker run -p 6379:6379 -v $PWD/data:/data ...

  9. 移动端video标签默认置顶的解决方案

    概述 在移动端上面,比如说微信上面打开一个页面,如果有video标签的话,常常会出现video标签默认置顶的情况,一般的解决方案是在不需要看见它的时候给它加一个display:none进行隐藏.今天在 ...

  10. LabVIEW(六):创建VI

    1.多使用快捷键,可以提高工作效率键盘快捷键 说明对象/动作Shift-单击 选取多个对象:将对象添加到当前选择之中.方向箭头键 将选中的对象每次移动一个像素.Shift-方向箭头键 将选中的对象每次 ...