3.1 C#程序是一组类型声明
- C#程序或DLL的源代码是一组一种或多种类型声明
- 对于可执行程序,类型声明中必须有一个包含Main方法的类
- 命名空间是一种把相关的类型声明分组并命名的方法
3.2 类型是一种模板
类型可以当成是一个用来创建数据结构的模板。模板本身并不是数据结构,但它详细说明了由该模板构造的对象的特征。
类型由以下元素定义:
- 名称
- 用于保存数据成员的数据结构
- 一些行为及约束条件
下例展示了short和int类型的组成元素:
名称 | 结构 | 行为 |
---|---|---|
short | 2字节 | 16位整数 |
int | 4字节 | 32位整数 |
3.3 实例化类型
从某个类型模板创建实际的对象,称为实例化该类型
- 通过实例化类型而创建的对象成为类型的对象或类型的实例
- 在C#程序中,每个数据项都是某种类型的实例。这些类型可以是语言自带的,可以 是BCL(基类库)或其他库提供的,也可以是程序员定义的。
3.4 数据成员和函数成员
某些类型可以包含许多不同类型的数据项。这些类型中的数据项个体称为成员。
- 数据成员:保存了与这个类的对象或作为一个整体的类相关的数据
- 函数成员: 执行代码。函数成员定义类型的行为。
下例列出了类XYZ的数据成员和函数成员
class XYZ
{
private int a = 1; //数据成员
private void F1() //函数成员
{
}
}
3.5 预定义类型
C#提供了16中预定义类型,这其中又包括13种简单类型和3种非简单类型。
所有预定义类型的名称都由全小写的字母组成。预定义简单类型包括以下3种:
- 11种数值类型
-› 不同长度的有符号和无符号整数类型
-› 浮点数类型float和double
-› 一种称为decimal的高精度小数类型。与float和double不同,decimal类型可以准确地表示分数。decimal类型常用于货币的计算。 - 一种Unicode字符类型char
- 一种布尔类型bool
3种非简单类型:
- string:是一个Unicode字符数组
- object:是所有其他类型的基类
-
dynamic:使用动态语言编写的程序集时使用
预定义类型分类图
所有预定义类型都直接映射到底层的.net类型。C#的类型名称就是.net类型的别名,所以使用.net的类型名称也能很好地符合C#语法,不过并不鼓励这样做。在C#程序中,应该尽量使用C#类型名称而不是.net类型名称。
下表是预定义简单类型对应的底层.NET类型:
名称 | 含义 | .NET框架类型 | 默认值 |
---|---|---|---|
sbyte | 8位有符号整数 | System.SByte | 0 |
byte | 8位无符号整数 | System.Byte | 0 |
short | 16位有符号整数 | System.Int16 | 0 |
ushort | 16位无符号整数 | System.UInt16 | 0 |
int | 32位有符号整数 | System.Int32 | 0 |
uint | 32位无符号整数 | System.UInt32 | 0 |
long | 64位有符号整数 | System.Int64 | 0 |
ulong | 64位无符号整数 | System.UInt64 | 0 |
float | 单精度浮点数 | System.Single | 0.0f |
double | 双精度浮点数 | System.Double | 0.0d |
bool | 布尔型 | System.Boolean | false |
char | Unicode字符串 | System.Char | \x0000 |
decimal | 小数类型的有效数字精度为28位 | System.Decimal | 0m |
下表是预定义非简单类型对应的底层.NET类型:
名称 | 含义 | .NET框架类型 |
---|---|---|
object | 所有其他类型的基类,包括简单类型 | System.Object |
string | 0个或多个Unicode字符所组成的序列 | System.String |
dynamic | 在使用动态语言编写的程序集时使用 | 无相应的.NET类型 |
3.6 用户定义类型
除C#提供的16种预定义类型外,还有6种可以由用户自己创建的类型:
- 类类型(class)
- 结构类型(struct)
- 数组类型(array)
- 枚举类型(enum)
- 委托类型(delegate)
- 接口类型(interface)
类型通过类型声明创建,类型声明包含以下信息:
- 要创建的类型的种类
- 新类型的名称
- 对类型中的每个成员的声明(名称和规格)。array和delegate类型除外,它们不含有命名成员。
一旦声明了类型,就可以创建和使用这种类型的对象,就像它们是预定义类型一样。
使用预定义类型只需一步:直接实例化对象即可
例:int a = 1;
使用用户定义类型需要两步:先声明类型,再实例化该类型的对象
例:AClass a; ->声明 a = new AClass();->实例化
3.7 栈和堆
程序运行时,数据必须存储在内存中。
运行中的程序使用两个内存区域来存储数据:栈和堆
3.7.1 栈
栈时一个内存数组,是一个LIFO(Last-In First-Out,后进先出)的数据结构。栈存储以下几种类型的数据:
- 某些类型变量的值
- 程序当前的执行环境
- 传递给方法的参数
系统管理所有的栈操作。程序员不需要显示地对它做任何事情。
栈的特征:
- 数据只能从栈的顶端插入和删除
- 把数据放到栈顶称为入栈
- 从栈顶删除数据称为出栈
3.7.2 堆
堆是一块内存区域,在堆里可以分配大块的内存用于存储某类型的数据对象。与栈不同,堆里的内存能够以任意顺序存入和移除。
虽然程序可以在堆里保存数据,但不能显式地删除它们。CLR(Common Language Runtime)的自动GC在判断出程序地代码将不会再访问某数据项时,会自动清除无主的堆对象。
3.8 值类型和引用类型
数据项的类型定义了存储数据需要的内存大小及组成该类型的数据成员。类型还决定了对象在内存中的存储位置——栈和堆。
类型分为两种:值类型和引用类型,这两种类型的对象在内存中的存储方式不同。
- 值类型只需要一段单独的内存,用于存储实际的数据
- 引用类型需要两段内存
第一段存储实际的数据,它总是位于堆中
第二段是一个引用,指向数据在堆中的存放位置,位于栈中
值类型,数据存放在栈中
引用类型,数据存放在堆中,引用存放在栈中 引用类型存储图
3.8.1 存储引用类型对象的成员
- 引用类型对象的数据部分始终存放在堆中
- 值类型对象,或引用类型数据的引用部分可以存放在堆中,也可以存放在栈中,这依赖于实际环境
例如,有一个引用类型的实例MyType,有两个成员:一个值类型成员和一个引用类型成员。
对于一个引用类型,其实例的数据部分始终存放在堆中。这两个成员都是对象数据的一部分,则它们都会被存放在堆中,无论它们是值类型还是引用类型。
- 尽管成员A是值类型,但它也是MyType实例数据的一部分,因此和对象的数据一起被存放在堆里
-
成员B是引用类型,所以其数据部分会始终存放在堆里,不同的是,其引用部分也会被存放在堆里,封装在MyType对象的数据部分中
引用类型成员数据存储
说明
对于引用类型的任何对象,它所有的数据成员都存放在堆中,无论是值类型还是引用类型
3.8.2 C#类型的分类
值类型 | 引用类型 | |
---|---|---|
预定义类型 | sbyte byte float short ushort double int uint char long ulong decimal bool |
object string dynamic |
用户定义类型 | struct enum |
class interface delegate array |
3.9 变量
C#提供了4种变量
名称 | 描述 |
---|---|
本地变量 | 在方法的作用域保存临时数据,不是类型的成员 |
字段 | 保存和类型或类型实例相关的数据,是类型的成员 |
参数 | 用于从一个方法到另一个方法传递数据的临时变量,不是类型的成员 |
数组元素 | (通常是)同类数据项构成的有序集合的一个成员,可以为本地变量, 也可以为类型的成员 |
变量在使用之前必须声明。变量声明定义了变量,并完成两件事:
- 给变量命名,并为它关联一种类型
- 让编译器为它分配一块内存
无初始化语句的本地变量有一个未定义的值,在未赋值之前不能使用
下表展示了哪种类型的变量会被初始化及哪种不会被初始化
变量类型 | 存储位置 | 自动初始化 | 用途 |
---|---|---|---|
本地变量 | 栈或者栈和堆 | 否 | 用于函数成员内部的本地计算 |
类字段 | 堆 | 是 | 类的成员 |
结构字段 | 栈或堆 | 是 | 结构的成员 |
参数 | 栈 | 否 | 用于把值传入或者传出方法 |
数组元素 | 堆 | 是 | 数组的成员 |
网友评论