第六章 类型和成员基础
- 不显示 定义类型的public或private,会默认为internal
成员访问性定义
- 规则C# → CLR
- protected → Family
- internal → Assembly
- 其他都差不多public → Public这样的
- CLR方法调用指令(这里是原文说的):
call
该 IL 指令可调用静态方法、实例方法和虚方法。用 call 指令调用静态方法,必须指定方法的定义类型。用 call 指令调用实例方法或虚方法,必须指定引用了对象的变量。call指令假定该变量不为null。换言之,变量本身的类型指明了方法的定义类型。如果变量的类型没有定义该方法,就检查基类型来查找匹配方法。call指令经常用于以非虚方式调用虚方法。callvirt
该 IL 指令可调用实例方法和虚方法,不能调用静态方法。用 callvirt 指令调用实例方法或虚方法,必须指定引用了对象的变量。用 callvirt 指令调用非虚实例方法,变量的类型指明了方法的定义类型。用 callvirt 指令调用虚实例方法,CLR 调查发出调用的对象的实际类型,然后以多态方式调用方法。为了确定类型,发出调用的变量绝不能是 null。换言之,编译这个调用时,JIT 编译器会生成代码来验证变量的值是不是null。如果是, callvirt 指令的执行速度比 call 指令稍慢。注意,即使 callvirt 指令调用的是非虚实例方法,也要执行这种null检查。
下面调用虚方法GetHashCode和非虚方法GetType都是用了`callvirt `,
C#团队认为JIT应当生成代码来检验对象是否为null,这样会使得调用虚方法会慢一点。
.method public hidebysig static void Main() cil managed {
.entrypoint
.maxstack 1
.locals init (object o)
IL_0000: call void System.Console::WriteLine()
IL_0005: newobj instance void System.Object::.ctor()
IL_000a: stloc.0
IL_000b: ldloc.0
IL_000c: callvirt instance int32 System.Object::GetHashCode()
IL_0011: pop
IL_0012: ldloc.0
IL_0013: callvirt instance class System.Type System.Object::GetType()
IL_0018: pop
IL_0019: ret
}
- 上面我们知道调用虚方法时将会以多态的方式来调用。但是如果类型时密封类
sealed
,JIT 编译器看到使用密封类型的虚方法调用,就可采用非虚方式调用虚方法,从而生成更高效的代码。之所以能这么做,是因为密封类自然不会有派生类。 安全性和可预测性
派生类可以访问更改基类状态、派生类可以重写和调用基类虚方法。一旦将某个方法、属性或事件设为 virtual,基类就会丧失对它的行为和状态的部分控制权。
第七章 常量和字段
- 常量会被看成static。并且在运行时常量的值是直接
嵌入
IL代码中,运行时不会给常量分配内存。
e.g. 如果A.dll中定义了常量,工程使用了这个常量。如果A修改常量数值,重写生成dll,但是不会得到修改后的常量,必须重写编译。如果需要运行时修改可以定义为static readonly
字段术语
- 规则C# → CLR
- static → Static
- readonly → InitOnly
- volatile → Volatile
- readonly的引用字段,是引用无法改变,而引用的对象是可以改变的
第八章 方法
- System.Object.MemberwiseClone() 将会分配内存,初始化附加字段,然后将源对象的字节数据复制到新对象中。
值类型和构造方法
下面在new Rectangle(),不会调用Point的无参构造方法,所以最后m_topLeft.m_x会被初始化为0
internal struct Point {
public Int32 m_x, m_y;
public Point() {
m_x = m_y = 5;
}
}
internal sealed class Rectangle {
public Point m_topLeft, m_bottomRight;
public Rectangle(){
}
}
- 注意上面的结构定义
无参构造方法
是会报错的,并且如果要定义构造方法,必须初始化所有字段,看下面
struct Point
{
public readonly int x;
public readonly int y;
public Point(int x)
{
this = new Point();
this.x = x;
}
}
static void Main(string[] args)
{
Point p = new Point(2);
Console.WriteLine($"{p.x}-{p.y}");
}
- static 类名/结构名 这个叫
类型构造器
- 操作符对应CLR方法如下:

转换操作符
- public static implicit operator Rational(Int32 num) 隐式转换
- public static explicit operator Int32(Rational r) 显式转换