正文
值类型和引用类型
值类型派生自System.ValueType,分配在栈上,不能被继承,变量默认按值传递,当它们超出定义的作用域时被回收。
引用类型分配在托管堆上,变量指向实例所占的内存地址,变量默认按引用传递(变量的地址传入被调用的函数),托管堆被垃圾回收时变量消亡。
传值与传址
按值传递值类型,被调用者不能改变参数值;按引用传递值类型,可以改变参数值。
如果按值传递引用类型,被调用者可能改变对象的状态数据的值,但不能改变所引用的对象,即不能让对象指向另外一个对象。
如果按引用传递引用类型,被调用者可能改变对象的状态数据的值和所引用的对象。
参数修饰符out和ref的区别
out: 调用方法之前不需要初始化,输出参数由被调用的方法赋值,如果被调用的方法没给输出参数赋值,会出现编译错误。
ref: 调用者赋初值,并且可以由被调用方法(可选地)重新赋值。
Internal和protected作用范围
Internal: 只能在包含它的程序集中访问该方法
Protected: 只有派生的类型和该类本身能访问该方法。
Protected internal: 只能在包含它的程序集,和派生类的代码中访问。
Using关键字
Using关键字用来:确保在对象引用超出作用域时,在实现了IDisposable接口的对象上自动调用Dispose()方法,实现资源回收。
静态构造函数
静态构造函数适用于初始化在编译时未知的静态数据值,例如,需要从外部文件/数据库读取或生成随机数等。一个类只能定义一个静态构造函数,静态构造函数只执行一次,静态构造函数的执行优先于任何实例级别的构造函数。
垃圾回收
在使用.NET进行托管编程时,不需要对托管堆进行直接操作。如果托管堆没有足够的内存来分配请求的对象,GC就会进行垃圾回收。
重写Finialize()的唯一原因是,C#类通过PInvoke或COM互操作性使用了非托管资源(如原始的操作系统文件句柄,数据库连接等)。
Finialize方法是保证垃圾回收时清除非托管资源。但对于数据库和文件句柄等非常宝贵的资源,应该尽快释放。除了重写Finialize()方法之外,可以实现IDisposable接口,它定义的Dispose方法可以由用户手工调用。
对象的代
垃圾回收时,CLR会试图寻找不可到达的对象,它不会逐个检查托管堆上的每一个对象。为了优化这个过程,堆上的每一个对象都属于某个代:
第0代:从没有标记为回收的新分配的对象
第1代:在上一次垃圾回收中没有被回收的对象
第2代:在一次以上的垃圾回收后仍然没有被回收的对象
垃圾回收器检查和处理所有的第0代对象,如果获得足够的空闲内存,就不用继续检查第1代和第2代的对象,同时没有被回收的对象被提升到第1代。
GAC
Global Assembly Cache是全局程序集缓存。大多数共享程序集都安装在这个缓存中,其中也安装了一些私有程序集。如果私有程序集使用本机图像生成器(Ngen.exe)编译为本机代码,也会存储在这个缓存中。
内部图像生成器(native image generator)Ngen.exe,可以在安装期间把IL代码编译为本机代码,这样程序启动更快。
正式的处置模式
public class MyResourceWrapper : IDisposable {
private bool disposed = false;
public void Dispose() {
CleanUp(true);
GC.SuppressFinalize(this);//跳过终结
}
private void CleanUp(bool disposing) {
if (!this.disposed) {
if (disposing) {
//释放托管的资源(在包含的可处置对象上调用Dispose)
}
//在这里释放非托管的资源
}
disposed = true;
}
~MyResourceWrapper() {
CleanUp(false);
}
}