《CLR via C#》读书笔记---06 类型和成员基础

核心知识归纳图
这里写图片描述

6-1 类型中成员的本质

这里写图片描述

  1. 颜色归一
    编译器支持了C#提供的各种各样的类型成员,CLR对其一无所知,都是IL代码

  2. 大小不同
    不同的类型成员因复杂度不同,编译器映射出的IL代码量也不尽相同

编译器对各种成员用一种“公共数据格式”来区分,可以视为是一种flag。编译器解析flag生成不同的IL。


6-2 类型的可见性

这里写图片描述

类型的可见性修饰符仅有两个:public && internal(default)

  • 语义:供所有类型使用 && 供程序集内所有类型使用

  • 当我试图为类型定义为private时,编译提示

    • 感悟:没有private修饰类型也是对的。实际中没有孤立存在的类型。实现了一个功能势必会让人调用。除非两种情况:一是没有用的代码;二是从Main到所有的功能都容纳在一个类型中,想来也是恐怖。

这里写图片描述


这里写图片描述

这里写图片描述

【语法】

B中引用using System.Runtime.CompilerServices;
在B的任意一个类型的命名空间上面加上[assembly: InternalsVisibleTo(“A”)]
这样A就可以见到B程序集中任意类型
语法参考 http://fwhyy.com/2010/11/csharp-a-friend-assembly/


6-3 成员的可访问性

这里写图片描述

CLR定义的关键字有6个,C#映射了其中5个

这里特别阐释一下:protected internal,被这个关键字(这都两个单词了)修饰的成员,可以被任何程序集中该类型派生类 或 定义程序集中的类型访问,这里是或的关系,意思是两者都可以。

CLR C# info
Private private 成员只能由定义类型或任何嵌套类型中的方法访问
Family protected 成员只能由定义类型、任何嵌套类型中的方法、任何程序集的派生类型方法访问
FamilyandAssembly
Assembly internal 成员只能由定义程序集中的方法访问
FamilyorAssembly protected internal 成员只能由定义类型、任何嵌套类型中的方法、任何程序集的派生类型方法、定义程序集中的方法访问访问
Public public 成员只能由任何程序集的任何方法访问

  • 想访问成员,其定义类型先可见(想吃糖,需要找到装糖的盒子)。遇到成员是public访问不了,也许原因就在这里
  • 成员访问不到报的错Exception有FiledAccessException && MethodAccessException
  • 提倡显示声明成员可访问性(隐式默认是限制最大的可访问性)
  • C#重写不可以变更可访问性;CLR允许重写放宽
    这里写图片描述
  • 接口的成员必须是public,默认也是public
    • 所以init的时候编译器已经做了这部分工作,这也是上面为什么说“通常”

这里写图片描述

  • 类型叫“可见性”,类型的成员叫”可访问性”
    • 我猜测:类型能看到就是能看到,很直接,叫“可见”,成员在类型之中,毕竟是包了一层,想想还是挺科学的。
    • 这里只是强调一下,虽然都用一个词,不能说叫错,但毕竟不专业,就像有些人对象和类型不分的叫。
  • 类型的可见性和成员的可访问性有必要谨慎定义吗?

6-4 静态类型

本质:sealed与abstract共同修饰
这里写图片描述

  • 不能继承、实现接口(abstract)
  • 没有.ctor(abstract)
  • 不能创建实例(sealded)
  • 成员皆静态,不能作为参数、字段、局部变量

当你若干时间后不记得这些特征,这是正常的事情,只需要记得“静态”,与类型实例相反

6.5 分部类型

  • 使用“partial”关键字,可以将一个类、接口、结构定义在多个文件中(不可跨程序集)
  • 本质:CLR对其一无所知
  • 好处:
    • 多个代码文件可以让多人同时编辑协作
    • 代码逻辑独立整理
    • 我们一个类中代码多,想给他分分类别整理,除了抽出去以外,可以整理放在多个文件中
    • WinForm中的disgner.cs和edit的地方就是一种使用

6.6组件、多态和版本控制

  • 什么是组件?

    • 做一个笔记本屏幕需要的玻璃,我们可以称它为屏幕的组件;做一个笔记本需要的屏幕,我们可以称它为笔记本的组件;出售一个笔记本时外面的纸箱子,外面可以称它为完整出售笔记本的组件……
    • 在开发中,一个字段、方法,可以是一个组件;一个控件、一个界面可以是一个组件;一个功能、一个模块是一个组件……
    • 在这里组件特别指的是“Assembly程序集”。一个Assembly是一个Component。像我们开发时候用过的一些三方的dll,像Dev、Donetbar、FastReport、Log4、NPOI……这些我们只需要引用几个组件就可以使用它们封装的功能,这些是对外公用的组件,里面包含了自己的开发信息,像版本号、公钥……;像我们开发项目里面的程序集,仅是私用,切割模块,大多没有定义那些开发信息
  • 维护版本期间做些什么?

    • 像我现在从事的软件开发,有些Realease期间就是发布一些小的版本,没有大功能,就是来修复堆积的bug和一些小功能的开发

    • 切记的是”克己”,不要去修改大的东西,不要自己看着一个有点规模或逻辑复杂的模块去重构,一方面时间是否够;一方面改的依赖多那测试的复杂度也是翻倍;另一方面影响接下来的进度和计划

    • 尤其修改基类务必谨慎,原因无他,牵扯依赖多
  • .NET Framework中提供的版本号怎么用?
    这里写图片描述

    • 主要和次要,代表某一个大的功能模块开发;内部版本和修订,代表在这个大的功能下不断的修复和增强

      • 例如v5.5.0.0中开发一个大的模块【考勤功能】,那v5.5.2.1、v5.5.2.12就是在考勤的方面的完善,想开发一个报表功能就变成v5.6.0.0
      • 这是当初设定的设计
    • 现在不同的公司不一样,只要能分清版本号就可以了。有的只用3位数字表达版本号;有的用奇偶数来表达不同含义的版本

  • 什么是版本变更?

    • 已发布软件的代码只要修改,那版本就算变更了。哪怕是没有意义的改变;哪怕修改的就是一个字段;哪怕只是Review代码的命名
  • 版本控制C#提供的5个关键字

C# info
abstract 抽象,修饰的类无法构造实例,修饰的方法无法有主体
virtual 这个成员可由派生类型重写
override 重写基类的成员
sealed 密封,修饰的类,无法被继承;与override结合修饰的属性和方法,其派生类无法重写该属性和方法
new 被修饰的子类成员和基类同名的成员没有关系,隐藏基类该成员

密封类中的虚方法调用性能大于非密封类中的虚方法。运行密封对象实例中虚方法,编译器知道该实例被密封了,少走虚方法的那套继承多态的路子,自然快了


====以下内容暂时保留,并不认同作者放在这里的意图,我会将其总结在第八章的方法中======
- 静态方法是对象的方法
- 重载
- CLR支持的重载:方法名相同,返回值类型、参数类型或参数类型顺序、个数不同
- C#支持的重载:返回值不计算入内
- 静态方法、虚方法、普通方法,编译器加入Flag做标记,对应生成不同的IL
- 尽量少的用虚方法
- 虚方法调用速度比普通速度慢
- 虚方法调用无法内联,速度更慢一点
- 虚方法导致版本维护脆弱
- 版本维护的重点是稳定中谋发展,虚方法的修改会涉及多个依赖,有不稳定的因素。
- 多态重载的方法技巧
- 可以将复杂的逻辑抽取一个虚方法,其他普通重载调用该虚方法
- 子类重写这个复杂的虚方法,调用父类相关重载的方法,最后调用的是子类的重写的方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章