C#类型分为两种:值类型和引用类型。
-
值类型和引用类型
值类型包括结构和枚举,引用类型包括了类,接口,委托等。还有一种特殊的值类型称之为简单类型。比如byte,int等,这些简单类型实际是BCL基类库的别名。
比如,声明一个类型int类型,实际上声明的是System.Int32结构类型。因此在Int32类型中定义的方法或属性都可以在int类型上使用。 比如123.Equals(2).
通过MSIL代码可以看到所有的值类型都隐式的继承自System.ValueType(本身是一个类类型)。System.ValueType类型和所有引用类型都继承自System.Object基类。
因为结构隐式的继承了System.VauleType,所有结构不支持继承(C#不支持多继承。)
-
值类型
结构的一个特性:调用结构上的方法之前,需要对其所有的字段复制,编译器隐式的为构造类型创建无参的构造函数,在这个构造函数中会对结构成员进行初始化,所以在结构不允许定义无参的构造函数。
public struct A()
{
public int x;
public void B(){}
}
通过隐式声明创建一个A类型变量
A a1=new A()
Console.WriteLine()
new操作符只是调用了A结构的默认函数,根据函数去初始化A结构的所有字段,并不分配内存和创建实例。
针对下面的情况
Cosnole.WriteLine((new A()).X)
这种情况,通过MISL观察会创建一个临时变量,然后使用结构的默认构造函数对此临时变量进行初始化。
-
引用类型
new操作符创建引用类型实例的时候,该引用类型的变量会被分配到线程栈上,实际保存了位于堆上的引用类型的实例的内存地址。变量本身不包含任何类型所定义的数据。
如果仅仅声明一个变量但是不使用new操作符,由于在堆上还没有创建类型的实例,因此变量值为null。意思是不指向任何对象(堆上的对象的实例)。
-
简单类型
结构属于自定义的值类型,不能用==来判断是否相等要用Equals()方法。当使用==的时候比较的实际是判断他们是否指向同一个对象。而这里并不是同一个对象,而是对象所含的值相同。
string是引用类型,运行下面代码
string a="1"
string b="1"
if(a==b)
{
Cosnole.WriteLine("a和b相同")
}
a,b不是执行同一对象所以条件为false,string是不可变类型。
-
装箱和拆箱
个人记忆,值类型一般说的时候不牵扯到内存地址,主要是比较值,,引用类型牵扯到内存地址,这里我把这个内存地址称之为箱。
值类型需要一个内存地址的引用来转换成引用类型所以称之为装箱(加了个引用地址)。相反的引用类型转成值类型就是拆箱了。(以上是个人记忆方法非官方语言解释)
拆箱是将一个已装箱的引用类型转换为值类型。拆箱操作需要两步,1,获取已经装箱的对象的地址。2,将值从堆上的对象中复制到堆栈上的值变量中。
以为拆箱和装箱反复在堆上操作所以,尽量避免没意义的装箱拆箱操作。
《.net之美》读书笔记