C#图解教程第3章_类型与函数参数
1. 预定义类型和用户定义类型
1)预定义类型
C#提供16种预定义类型,如下图所示。
tips:
- 与C++不一样,数值类型不具有布尔类型,如C++ 可以int a= 3,可以if(a)..;C#不行。
- dynamic类型在动态语言中使用,使用dynamic可以自定义添加不存在的属性和值,编译不会对它进行类型检查。var与之不同,对于var,编译器会自动为其替换对应类型。
2)用户定义类型
c#提供了6种用户定义类型:class,struct,array,enum,delegate,interface.
2. 值类型、引用类型,值参数,引用参数
1)堆和栈
介绍值参数和引用参数前,先介绍堆和栈的概念。堆和栈是指运行程序时,使用的存储数据的两个内存区域。栈是一个内存数组,遵循LIFO(后进先出)的数据结构,栈一般存储如下数据:
- 某些类型变量的值;
- 程序当前的执行环境
- 传递给方法的参数
栈的示意图如下:
堆也是一块内存区域,它相当于栈很大,一般用于存储大型数据,堆内数据能以任意顺序存入和删除。
堆的示意图如下:
2)值类型和引用类型
值类型:存储在栈上;
引用类型:类似于C++的指针,引用存储在栈上,实际数据存储在堆上。
C#的值类型和引用类型分类如下图:
tips:
- 对于值类型,它也有可能在堆上。如在类中(引用类型)定义了值类型,那么在类实例中,该值类型数据,还是在堆中,如下图(MyType类中定义了一个值类型A):
- 值类型都是struct,都继承于System.ValueType类,CLR对System.ValueType的派生类做了特殊处理,如使它内存分配方面具有值类型的特征,使其不能被继承(私有)等。
3. 值参数和引用参数
值参数:在方法调用时,在栈上先为形参分配空间,然后将实参的值复制给形参。
引用参数:类似于C++的引用,在方法调用的时候,不会在内存中分配空间,只会为实参分配一个别名。
tips:
- 引用参数声明和调用时必须都使用ref。
- 引用参数的实参必须是变量,且用做实参时必须被赋值(防止未被赋值时,报错,相对于C++的改进),COM编码时调用时可省略ref,需传一个值(非变量)。
- string比较特殊,虽然是引用类型,但作为值参传入函数时,string类型的变量在被赋予新值的时候,不会将原值擦去而填上新的值,而是会在堆中重新开辟空间,在空间中放入新的值,从而变量的地址也会改变,变成新空间的地址。
4.可空类型
某些情况下,你希望表示变量目前未保存有效值,对于引用类型可以用null表示,对于值类型,可以在定义时再类型后加上?,就也可以null表示未保存有效值;
int? a = null;
Nullable<int> a = null;