7.4.1 构造函数
在C#中,构造函数是一种特殊的方法,用于在创建对象时初始化对象。以下是构造函数的一些关键特性和规则:
-
构造函数的名称必须与类名完全相同:构造函数没有返回类型,甚至不使用
void
。 -
构造函数可以是公有的(public)、保护的(protected)或私有的(private):
public
:可以用于任何地方的实例化。protected
:只能在同一个程序集(Assembly)中的子类中被调用。private
:只能在定义它的类内部被调用。
-
构造函数的主要目的是初始化对象:它通常不执行除了设置字段值以外的其他操作。
-
构造函数在创建类的新实例时自动调用:你不能显式调用一个构造函数(除了在声明时)。
-
如果没有显式声明构造函数,编译器会提供一个默认构造函数:这个默认构造函数是无参数的。
-
构造函数可以重载:一个类可以有多个构造函数,只要它们的参数列表不同。
public class Person
{
public string m_name;
protected int m_age;
protected bool m_gender;
// 默认构造函数
public Person()
{
m_name = "Unknown";
m_age = 0;
m_gender = false;
}
}
Person
类有一个默认构造函数,它将m_name
初始化为"Unknown"
,m_age
初始化为0
,m_gender
初始化为false
。
public class Xyz {
// 成员变量
int x;
// 默认构造函数
public Xyz() {
x = 0; // 默认创建对象
}
// 带一个参数的构造函数
public Xyz(int i) {
x = i; // 使用参数创建对象
}
}
Xyz
类有两个构造函数:- 一个无参数的默认构造函数,它将
x
初始化为0
。 - 一个带有一个整型参数的构造函数,它使用传入的参数值来初始化
x
。
- 一个无参数的默认构造函数,它将
构造函数重载允许你在创建对象时提供不同的初始化选项。例如,你可以创建一个 Xyz
对象而不提供任何参数,x
将默认为 0
,或者你可以提供一个整数值来初始化 x
。
Xyz defaultXyz = new Xyz(); // x will be 0
Xyz specificXyz = new Xyz(5); // x will be 5
7.4.2 析构函数
在C#中,析构函数是一种特殊的方法,用于在对象的生命周期结束时进行清理工作。以下是析构函数的一些关键特性和规则:
-
析构函数不接受任何参数:它也没有返回值,甚至不使用
void
。 -
析构函数没有访问限制修饰符:它总是可以被访问。
-
析构函数的名称在类名前加一个波浪号(
~
):例如,如果类名为Person
,那么析构函数的名称就是~Person
。 -
析构函数的主要目的是销毁对象:它通常用于释放非托管资源,如文件句柄、数据库连接等。
-
析构函数不能被继承:每个类可以有自己的析构函数,但析构函数不会被派生类继承。
-
析构函数不能被显式调用:它们由垃圾回收器自动调用,当垃圾回收器确定对象不再被使用时。
以下是你提供的代码的解释:
public class Person
{
private string m_name;
private int m_age;
private bool m_gender;
// 析构函数
~Person()
{
// 在这里进行清理工作
}
}
Person
类有一个析构函数~Person()
。在这个析构函数中,你可以放置清理资源的代码。
析构函数通常用于释放非托管资源。在.NET中,大多数资源(如文件、网络连接等)都是托管的,这意味着它们由.NET的垃圾回收器自动管理。然而,有时你可能需要使用非托管资源,这时就需要在析构函数中进行清理。
以下是一个使用析构函数释放非托管资源的例子:
public class DatabaseConnection
{
private IntPtr nativeConnection; // 假设这是一个非托管资源
public DatabaseConnection(string connectionString)
{
// 建立数据库连接
nativeConnection = NativeMethods.CreateConnection(connectionString);
}
// 析构函数
~DatabaseConnection()
{
// 清理非托管资源
if (nativeConnection != IntPtr.Zero)
{
NativeMethods.CloseConnection(nativeConnection);
}
}
}
在这个例子中,DatabaseConnection
类使用了一个非托管资源 nativeConnection
。在析构函数中,我们检查 nativeConnection
是否已经被分配,并调用相应的清理函数。
注意事项
-
析构函数的调用时机是不确定的:你不能依赖析构函数来执行重要的清理工作,因为垃圾回收器的调用时机是不可预测的。
-
使用
IDisposable
接口:在.NET中,推荐使用IDisposable
接口来管理资源的释放。通过实现IDisposable
接口并提供一个Dispose
方法,你可以确保资源被及时释放。
public class DatabaseConnection : IDisposable
{
private IntPtr nativeConnection;
public DatabaseConnection(string connectionString)
{
nativeConnection = NativeMethods.CreateConnection(connectionString);
}
public void Dispose()
{
if (nativeConnection != IntPtr.Zero)
{
NativeMethods.CloseConnection(nativeConnection);
nativeConnection = IntPtr.Zero;
}
}
// 析构函数
~DatabaseConnection()
{
Dispose();
}
}
在这个改进的例子中,实现了 IDisposable
接口,并在析构函数中调用 Dispose
方法。这样,用户可以通过调用 Dispose
方法来显式释放资源,同时也可以通过垃圾回收器来隐式释放资源。