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之美》读书笔记