-
构造函数与析构函数
构造函数与析构函数
-
构造函数
构造函数是类的特殊方法,用于初始化对象,与类名完全一致,无返回值(连void都不能写)。它在对象创建vb.net教程C#教程python教程SQL教程access 2010教程时自动调用,确保对象处于合法初始状态。
1.1 默认构造函数
若类未显式定义构造函数,编译器会自动生成无参数的默认构造函数,用于初始化字段为默认值(如int为0,string为null)。
实例:
csharp
public class Person
{
// 私有字段
private string _name;
private int _age;
// 未显式定义构造函数 → 编译器自动生成默认构造函数
}
// 使用
Person p = new Person();
// 默认构造函数将_name初始化为null,_age初始化为0
注意:若显式定义了带参构造函数,编译器不再生成默认构造函数。如需无参构造,需手动添加:
csharp
public class Person
{
private string _name;
private int _age;
// 显式定义无参构造函数
public Person()
{
_name = "未知";
_age = 18; // 设置默认年龄
}
// 带参构造函数
public Person(string name, int age)
{
_name = name;
_age = age;
}
}
1.2 自定义构造函数
自定义构造函数通过参数传递初始化对象,直接给私有字段赋值,避免创建对象后多次调用属性赋值。
实例:
csharp
public class Person
{
private string _name;
private int _age;
// 自定义构造函数:带name和age参数
public Person(string name, int age)
{
// 用参数初始化字段(参数名与字段名不同,无需this)
_name = name;
_age = age;
}
// 公共方法:输出信息
public void Introduce()
{
Console.WriteLine($"我是{_name},今年{_age}岁");
}
}
// 使用
Person p = new Person("张三", 25);
p.Introduce(); // 输出:我是张三,今年25岁
逐行讲解:
public Person(string name, int age):构造函数名与类名一致,参数name和age用于接收初始化值。
_name = name:将参数name赋值给私有字段_name,确保对象创建时就有合法姓名。
new Person("张三",25):创建对象时,构造函数自动调用,完成初始化。
1.3 构造函数重载
构造函数支持重载(多个构造函数,参数数量/类型不同),实现多种初始化方式。
实例:
csharp
public class Person
{
private string _name;
private int _age;
// 重载1:无参构造(默认值)
public Person()
{
_name = "未知";
_age = 18;
}
// 重载2:仅姓名参数(年龄默认20)
public Person(string name)
{
_name = name;
_age = 20;
}
// 重载3:姓名+年龄参数
public Person(string name, int age)
{
_name = name;
_age = age;
}
public void Introduce()
{
Console.WriteLine($"我是{_name},今年{_age}岁");
}
}
// 使用
Person p1 = new Person(); // 调用重载1 → 未知,18
Person p2 = new Person("李四"); // 调用重载2 → 李四,20
Person p3 = new Person("王五",30); // 调用重载3 → 王五,30
规则:重载构造函数的参数必须满足数量不同或类型不同(顺序不同也算,但不推荐,易混淆)。
1.4 this关键字:解决参数与字段重名
若构造函数参数名与字段名相同,需用this关键字指代当前对象的字段,避免歧义。
实例:
csharp
public class Person
{
private string _name;
private int _age;
// 参数名与字段名相同 → 用this区分
public Person(string name, int age)
{
this._name = name; // this._name → 当前对象的_name字段
this._age = age;
}
}
1.5 静态构造函数
静态构造函数用static修饰,用于初始化静态成员(类级别的数据,所有对象共享)。
核心特性:
无参数,只能有一个;
类第一次被使用时自动调用一次(不管创建多少对象);
无法手动调用。
实例:
csharp
public class Person
{
// 静态字段:记录创建的对象总数
public static int TotalCount;
// 静态构造函数:初始化静态字段
static Person()
{
TotalCount = 0;
Console.WriteLine("静态构造函数被调用");
}
// 实例构造函数:每次创建对象时自增总数
public Person()
{
TotalCount++;
Console.WriteLine($"实例构造函数被调用,当前总数:{TotalCount}");
}
}
// 使用
Person p1 = new Person();
// 输出:静态构造函数被调用 → 实例构造函数被调用,当前总数:1
Person p2 = new Person();
// 输出:实例构造函数被调用,当前总数:2(静态构造函数不再调用)
-
析构函数
析构函数(Finalize方法)用于释放对象占用的非托管资源(如文件句柄、数据库连接、Win32 API分配的内存)。它由垃圾回收器(GC)自动调用,执行时机不确定。
2.1 语法与实例
析构函数用~+类名定义,无参数、无访问修饰符、无返回值。
实例:释放文件资源
csharp
public class FileHandler
{
private FileStream _stream;
// 构造函数:打开文件
public FileHandler(string filePath)
{
_stream = new FileStream(filePath, FileMode.Open);
Console.WriteLine("文件已打开");
}
// 析构函数:释放文件资源
~FileHandler()
{
if (_stream != null)
{
_stream.Close();
Console.WriteLine("析构函数释放文件资源");
}
}
}
// 使用
FileHandler fh = new FileHandler("test.txt");
fh = null; // 让对象成为GC回收目标
GC.Collect(); // 强制GC回收(仅测试用,实际不推荐)
GC.WaitForPendingFinalizers(); // 等待析构函数执行
// 输出:析构函数释放文件资源
2.2 局限性
析构函数的执行时机完全由GC决定,可能延迟很久才执行,甚至程序退出前都不执行。因此:
不推荐依赖析构函数释放资源;
仅用于释放非托管资源(托管资源由GC自动回收);
无法手动调用。
3. 基础知识拓展
3.1 构造函数执行顺序
静态构造函数 → 父类实例构造函数 → 子类实例构造函数;
子类构造函数默认调用父类的无参构造函数,如需调用带参构造,用base(参数):
csharp
public class Animal
{
public Animal(string type)
{
Console.WriteLine($"Animal类型:{type}");
}
}
public class Dog : Animal
{
// 调用父类带参构造函数
public Dog() : base("哺乳动物")
{
Console.WriteLine("Dog构造函数");
}
}
// 使用 → 输出:Animal类型:哺乳动物 → Dog构造函数
Dog dog = new Dog();
3.2 析构函数执行顺序
子类析构函数 → 父类析构函数(与构造函数相反)。
3.3 推荐:用IDisposable释放资源
因析构函数执行时机不确定,实际开发中优先用IDisposable接口手动释放资源,配合using语句自动调用Dispose方法。
实例:
csharp
// 实现IDisposable接口
public class FileHandler : IDisposable
{
private FileStream _stream;
private bool _disposed = false; // 标记是否已释放
public FileHandler(string filePath)
{
_stream = new FileStream(filePath, FileMode.Open);
}
// 手动释放资源的方法
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this); // 告诉GC无需再调用析构函数
}
// 受保护方法:处理托管/非托管资源
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
// 释放托管资源(如_stream)
_stream?.Close();
}
// 释放非托管资源(如Win32句柄)
_disposed = true;
}
}
// 析构函数:仅在未手动Dispose时调用
~FileHandler()
{
Dispose(false);
}
}
// 使用using语句 → 自动调用Dispose
using (FileHandler fh = new FileHandler("test.txt"))
{
// 处理文件逻辑
}
// 离开using块时自动释放资源
总结
构造函数:初始化对象,分默认、自定义、静态三种,this解决参数与字段重名;
析构函数:释放非托管资源,执行时机不确定,不推荐依赖;
最佳实践:用IDisposable+using手动释放资源,确保及时、可靠。
本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49360.html










