Chapter4 类型基础

4.1 所有类型都是从System.Object派生

CLR要求所有对象都用new操作符来创建
Employee e=new Employee("ConstructorParam1");
new操作符所做的事情:
1.计算类型以及所有基类中定义的实例字段所需要的字节数
2.在托管堆中分配指定类型要求的字节数,分配对象的内存
3.它初始化对象的“类型对象指针”和“同步块索引”成员
4.调用类型的实例构造器,编译器会在构造器中自动生成代码来调用一个基类构造器,每个类型的构造器负责初始化有这个类型定义的实例字段,最终调用System.Object的构造器
new 执行了所有这些操作之后,会返回指向新建对象的一个引用,这个引用保存在变量e中

4.2类型转换

CLR允许一个对象转换为它的实际类型或者它的基类型。
类型安全性测验:
internal class B{} //基类
internal class D:B{} //派生类
表格:

语句 编译成功和执行 编译时错误 运行时错误
Object o1=new Object();    
Object o2=new B();    
Object o3=new D();    
Object o4=o3;    
B b1=new B();    
B b2=new D();    
D d1=new D();    
B b3=new Object();    
D d2=new Object();    
B b4=d1;    
D d3=b2;    
D d4=(D)d1;    
D d5=(D)b2;    
D d6=(D)b1;    
B b5=(B)o1;    
B b6=(D)b2;    

使用C#is和as操作符来转型
is:检查一个对象是否兼容于指定的类型,并返回一个Boolean值,is永远不会抛出异常
if(o is Employee){
Employee e=(Employee)o;
//if语句剩余的部分中使用e
}
as:如果兼容指定类型就返回一个指定类型非null的引用,不兼容,返回null
Employee e=o as Employee;
if(e!=null){
//在if语句中使用e
}
一般情况as用的比较多,因为使用is会检查两次对象的类型,首先核实o是否兼容Employee,如果是执行if内语句在核实o是否引用一个Employee。性能没有as高。

4.3命名空间和程序集

C# using 指令
潜在问题:可能有两个或多个类型在不同的命名空间中具有相同的名称
例如:Microsoft下有个Widget的类型,Wintellect下也有个Widget的类型
using Microsoft;
using Wintellect;

Widget w=new Widget(); //一个不明确的引用
解决方案:
//将WintellectWidget定义成Wintellect.Widget的别名
using WintellectWidget=Wintellect.Widget;
注意:命名空间和程序集(实现了一个类型的文件)不一定是相关的。特别是,同一个命名空间中的各个类型可能是在不同的程序集中实现的。
例如System.IO.FileStream类型是在MSCorLib.dll程序集中实现的,而System.IO.FileSystemWatcher是在System.dll中实现的。

4.4运行时相互联系

1.类型、对象、线程栈和托管堆在运行时的相互关系
线程栈:1个线程创建时,会分配一个1MB大小的栈,这个栈的空间用于向方法传递实参,并用于方法内部定义的局部变量。
由于线程栈是从高位开始分配内存,先分配的我就画在上面了,在调用M1()方法时,分配内存的顺序是:name->s->M2的返回地址->length->tally;
回收内存的顺序当然是反过来的。在一个方法中,应该包含一些序幕代码,进行一些初始化工作,还有一些尾声代码,等方法执行完成之后做一些回收工作。
由于方法的返回地址先分配,在方法执行完成的时候回到返回地址,递归太深就容易出现栈溢出,因为参数、局部变量都必须等到方法返回的时候才能回收。
2.调用静态方法、实例方法和虚方法的却别
假设有2个类定义:

internal class Person
{
private int height;
//实例方法
public void SetHeight(int height)
{
this.height = height;
}
//虚方法
public virtual void Say(string word) { }
//静态方法
public static string Head()
{
return "my head";
}
public static int Age = 10;
}
internal class Student : Person
{
public override void Say(string word)
{
Console.WriteLine(word); ;
}
}
现在马上就要调用Main入口方法:
static void Main(string[] args)
{
Person student = new Student();
student.Say("Hello cth");
student.SetHeight(172);
Person.Head();
Console.ReadLine();
}

1.JIT将Main的IL代码转换成本地CPU指令,然后将内部引用的所有类型的程序集加载,然后创建数据结构来表示类型本身,如图所示

2.当CLR确定方法需要的所有类型对象都以创建,开始允许线程执行Main的本地代码,然后Main执行它的代码来构造一个Student对象,这造成托管堆中创建了Student的一个实例
略。。。。以后单独拿出一篇来介绍

原文地址:https://www.cnblogs.com/hailiang2013/p/2856301.html