Files
My-Notes/笔记/CSharp/核心/构造函数、析构函数、垃圾回收.md
T
2026-06-21 09:51:55 +08:00

4.0 KiB
Raw Blame History

构造函数

概念:

  • 构造函数用于在对象创建时做初始化
  • 构造函数名必须和类名相同
  • 构造函数没有返回值类型
  • ==可以重载==

通常用法:

  • 给字段或属性设置初始值
  • 保证对象一创建出来就处于可用状态

语法:

访问修饰符 类名(参数列表)
{
}

案例:

class Person
{
	public string Name;
	public int Age;

	public Person()
	{
		Name = "默认值";
		Age = 0;
	}

	public Person(string name, int age)
	{
		Name = name;
		Age = age;
	}
}

this 调用其他构造函数:

class Person
{
	public string Name;
	public int Age;

	public Person() : this("默认值", 0)
	{
	}

	public Person(string name, int age)
	{
		Name = name;
		Age = age;
	}
}

注意:

  1. ==如果类里完全没写任何实例构造函数,编译器才会自动补一个无参构造函数==
  2. ==只要你自己写了任意实例构造函数,默认无参构造函数就不会再自动生成==
  3. 构造函数通常写 public,但也可以根据设计写成 private / protected
  4. 子类构造函数可以通过 base(...) 调用父类构造函数

析构函数

概念:

  • C# 里的析构函数更准确地说是==终结器(finalizer==
  • 当对象即将被 GC 回收时,运行时可能会调用它
  • 它主要用于“兜底清理非托管资源”

语法:

class Person
{
	~Person()
	{
		// 清理代码
	}
}

注意:

  1. 析构函数只能写在==类==里,结构体不能写
  2. 不能手动直接调用析构函数
  3. 析构函数执行时机==不确定==
  4. 大多数业务代码里==不推荐为了练习而滥写析构函数==
  5. 现代 .NET 中,更常见的做法是优先使用 IDisposableusingSafeHandle

垃圾回收

垃圾回收(GC):

  • GC 是 .NET 的自动内存管理机制
  • 它负责识别哪些托管对象还“活着”,哪些已经不可达,可以回收

基础理解:

  1. 只要对象还能从“根”访问到,就一般不会被回收
  2. 访问不到的对象,才有机会被 GC 回收
  3. GC 主要管理的是==托管堆上的对象==

分代概念:

  • .NET GC 常分为 0、1、2 代
  • 新对象一般先进入 0 代
  • 活得越久,越可能被提升到更高代
  • 大对象通常会进入 LOH(大对象堆),阈值常见记法是 >= 85,000 字节

注意:

  1. ==GC.Collect() 一般不建议手动乱调==
  2. 手动触发 GC 可能带来性能抖动
  3. “值类型一定在栈上、引用类型一定在堆上”不是绝对规则
  4. GC 解决的是==托管内存==问题,不等于所有资源都会自动及时释放

GC 和 IDisposable

首先区分资源类型:

  • 托管资源 比如普通对象、字符串、集合。主要由 GC 管理。
  • 非托管资源 比如文件句柄、数据库连接、Socket、窗口句柄。需要更及时地手动释放。

为什么要用 IDisposable

  • 因为 GC 只负责“对象内存”回收
  • 但像文件、连接、句柄这类资源,经常需要你主动关闭

最常见写法:

using var stream = new FileStream("demo.txt", FileMode.OpenOrCreate);
// 使用 stream

说明:

  • using 结束时会自动调用 Dispose()
  • 这比“等 GC 什么时候想起来再收”更可靠

标准释放模式示意:

public class MyResource : IDisposable
{
	private bool _disposed;

	public void Dispose()
	{
		Dispose(true);
		GC.SuppressFinalize(this);
	}

	protected virtual void Dispose(bool disposing)
	{
		if (_disposed) return;

		if (disposing)
		{
			// 释放托管资源
		}

		// 释放非托管资源
		_disposed = true;
	}

	~MyResource()
	{
		Dispose(false);
	}
}

补充理解:

  1. Dispose() 是“我现在就主动释放”
  2. 析构函数是“万一你忘了,我最后帮你兜底一次”
  3. GC.SuppressFinalize(this) 的意思是: 这个对象已经手动释放好了,不用再走终结器那一套

复习重点:

  • GC 管托管内存
  • Dispose 管需要及时释放的资源
  • 最常用姿势不是手写 GC.Collect(),而是优先写好 using / Dispose

#封装 #核心