.net框架那本书已读过几遍,但仍有一下地方的知识被遗漏.
重读此书,主要摘录了<<Clr Via C#>>中有些自己不知,或容易忽略的技术要点
前1-3章未读先跳过了
第4章
1) 认为GetHashCode不应该定义在Object类中,因为大多类不会在Hash Table中当key使用.应该设计成一个Interface,当需要做key时,去实现这样的interface就好了
2) CLR创建对象时都需要使用New操作符. (应该不全是,在后面的章节中有提到)
3) New操作符做了哪些事:
- 计算对象实例需要的内存空间.类自身定义的fields以及基类定义的fields,附带两个额外的成员: a.指向类型的指针 b. 用于同步的index(sync block index, 用于管理对象)
- 分配内存,将所有字节付0
- 初始化两个额外的成员
- 调用实例构造函数.
- 返回一个地址指针给变量
4) 实例构造函数会依次先调用基类的无参构造函数,每个构造函数负责初始化自身定义的Fields
5) CLR是类型安全的,所以在运行时总是知道对象的确切类型
6) CLR根本就不知道namespaces的存在,因此当它需要访问一个类型时,它需要知道此类型的完整名字.这点可以通过ildasm.exe工具查看生成的IL代码.所谓的别名也只是告诉编译器如何得到类型的完整名.
7) 一个thread被创建,会为其在stack上分配1MB空间.此空间用于传递参数,创建局部变量等.
8)
第5章
9) 应该为值类型重写Equals方法.因为ValueType是通过reflector实现Equals方法的,严重影响性能
10) C#编译器不允许值类型实现Finalize方法
11) System.Runtime.InteropServices.StructLayoutAttribute可以为类声明字段的布局方式
12) 如何在AppDomain里生成唯一的ID: 通过System.Runtime.CompilerServices.RuntimeHelpers类的GetHashCode()方法
13) ValueType实现GetHashCode使用reflection以及XOR一些字段.(实际上不完全是这样.应该是返回第一个不为null的field的hash code)
第6章
14) Friend Assemblies : 一般来说类型定义为internal访问权限的话,此成员只能被同一assembly其它类型访问.但由于某些特殊原因, 特定的另一个assembly成员想要访问次internal成员类型,那么就可以使用此技术
Using System.Runtime.CompilerServices
[assembly : InternalsVisibleTo(“assembly name, assembly key”)]
15) 子类型想要覆盖父类型的成员时, 在C#里他们的访问权限定义的必须一致.在CLR里,子类型还可以降低访问权限.
16) Static Class : 一直没注意原来C#也有静态类型.
静态类型约束:
Ø 此类型必须直接继承自Object.因为此类型没有实例,所以继承自其它类型没有任何意义.
Ø 不能实现任何interface
Ø 只能定义静态成员
Ø 此类型不能被用于私有成员,方法参数,局部变量.
17) 一般来说对于非虚方法使用call指令,对于虚方法使用callvirt指令.callvisrt指令会去检测当前对象是不是null,而且还需要查表,因此会慢一点.
object o = new object();
Type t = o.GetType();
查看IL却发现实际上是使用callvirt指令的,为何呢?这是C#编译器为了保证o对象不为空,因为callvirt指令会去检测o对象是否为null,而call指令不会.当JIT发现callvirt指令调用方法时,发现此方法不是虚方法,就会调用它的非虚方法,不需要再去查表.
18) 有时候编译器也会用call指令代替callvirt指令去调用虚方法.例如调用对象的ToString()方法.如何用callvirt指令去调用,会出现死循环(??why)
19) 优先使用非虚方法:
Ø 调用虚方法要慢
Ø 虚方法不能被inline
Ø 虚方法使得版本控制更复杂
20) Jeff认为除了sealed之外应该增加closed来修饰class,子类不可以修改父类的任何行为,但可以扩充.
21) 当事情变得越来越负责的时候,添加更多的类
22) 标记一下: 字段前面还可以加volatile修饰, 表示字段可能被多个并发执行线程修改。声明为 volatile 的字段不受编译器优化(假定由单个线程访问)的限制。这样可以确保该字段在任何时间呈现的都是最新的值。