C#基础补充
A.对值类型的分配。
虚拟内存中存在一个叫堆栈的区域,我们并不知道它到底在地址空间的什么地方,在一般开发过程中也没有必要知道,我们知道的是值类型就分配于此。值类型在堆栈上分配的时候,是自上而下填充的,也就是从高内存地址开始填充。
比如当前的堆栈指针为100000,这表明它的下一个自由存储空间从99999开始,当我们在C#中声明一个int类型的变量A,因为int类型是四个字节,所以它将分配在99996到99999这个存储单元中。如果我们接着声明double变量B(8字节),该变量将分配在99988到99995这个存储单元。 如果代码运行到他们的作用域之外,这时候A和B两个变量都将被删除,此时的顺序正好相反,先删除变量B,同时堆栈指针会递增8,也就是重新指向到99996这个位置;接下来删除变量A,堆栈指针重新指向10000。如果两个变量是同时声明的。如int A,B,此时我们并不知道A和B的分配顺序,但是编译器会确保他们的删除顺序正好和分配顺序相反。
B.对引用类型的分配。
了解堆栈上的分配方式之后,很明显,它的性能相当高,同时我们也发现了它的一个缺点:变量的生存期必须嵌套。这对于某些情况来说是无法接受的,有时候我们需要存储一些数据并且在方法退出后仍然能保证这部分数据是可以使用的。为此,虚拟内存另外分配了一部分区域,我们称之为托管堆。托管堆和传统的堆很大的一个不同点在于,托管堆在垃圾收集器的控制下进行工作。引用类型就分配在托管堆上,下面我们来看看引用类型的分配过程。
假设我们需要声明一个Person类并对它进行实例化。
Person p = new Person();
首先, 系统会在堆栈上给p这个变量在堆栈上分配存储空间,当然它只是一个引用而已,用来存放Person实例在托管堆上的位置,并没有存放真正的Person实例。因为它仅仅是存放一个地址(一个整数值),所以它将在堆栈上占据4个字节的空间。接下来Person实例将会被存放在托管堆上。和堆栈不同,托管堆是由下往上分配的,假设这个实例需要占据10个字节,假设托管堆上的地址为200000,那么它将分配在200000到200009这个存储单元。
需要注意的是,这个分配和实例的大小有关,如果实例小于85000字节,它会被分配在托管堆。如果超过了85000字节,它将被分配在LOH上 。
C#语言不支持多重继承。
1.4.3 结构类型
结构类型和类一样,可以声明构造函数、数据成员、方法、属性等。结构和类的最根本的区别是结构是值类型,类是引用类型。和类不同,结构不能从另外一个结构或者类派生,本身也不能被继承,因此不能定义抽象结构,结构成员也不能被访问权限控制字protected修饰,也不能用virtual和abstract修饰结构方法。在结构中不能定义析构函数。虽然结构不能从类和结构派生,可是结构能够继承接口,结构继承接口的方法和类继承接口的方法基本一致。下面例子定义一个点结构point:
using System;
struct point//结构定义
{
public int x,y;//结构中也可以声明构造函数和方法,变量不能赋初值
}
class Test
{
static void Main()
{
point P1;
P1.x=166;
P1.y=111;
point P2;
P2=P1;//值传递,使P2.x=166,P2.y=111
point P3=new point();//用new生成结构变量P3,P3仍为值类型变量
}//用new生成结构变量P3仅表示调用默认构造函数,使x=y==0。
}
修饰符:
一个 访问修饰符 定义了一个类成员的范围和可见性。C# 支持的访问修饰符如下所示:
- public:所有对象都可以访问;
- private:对象本身在对象内部可以访问;
- protected:只有该类对象及其子类对象可以访问
- internal:同一个程序集的对象可以访问;
- protected internal:访问限于当前程序集或派生自包含类的类型。
using的用法:
1. using指令:引入命名空间
这是最常见的用法,例如:
using System;
using Namespace1.SubNameSpace;
2. using static 指令:指定无需指定类型名称即可访问其静态成员的类型
using static System.Math;var = PI; // 直接使用System.Math.PI
3. 起别名
using Project = PC.MyCompany.Project;
4. using语句:将实例与代码绑定
using (Font font3 = new Font("Arial", 10.0f),
font4 = new Font("Arial", 10.0f))
{
// Use font3 and font4.
}
代码段结束时,自动调用font3和font4的Dispose方法,释放实例。
关于构造函数的补充:
对于父类与子类来讲,子类在调用构造函数时会首先调用父类构造函数再调用子类构造函数。同样的,如果是多次继承,那么后面的子类调用构造函数时会从最上面的父类的构造函数开始调用一次往下,直到自己的构造函数。
枚举
C# 枚举学习需要注意:
System.Enum 类型是所有枚举类型的抽象基类(它是一种与枚举类型的基础类型不同的独特类型),并且从 System.Enum 继承的成员在任何枚举类型中都可用。存在从任何枚举类型到System.Enum 的装箱转换,并且存在从 System.Enum 到任何枚举类型的取消装箱转换。System.Enum 本身不是枚举类型。相反,它是一个类类型,所有枚举类型都是从它派生的。类型 System.Enum 从类型 System.ValueType派生,而后者又从类型 object 派生。在运行时,类型 System.Enum 的值可以是 null 或是对任何枚举类型的装了箱的值的引用。