目录
构造函数和析构函数是类中比较特殊的两种成员函数,主要用来对对象进行初始化和回收对象资源。
一般来说,对象的生命周期从构造函数开始,以析构函数结束。如果一个类含有构造函数,在实例化该类的对象时就会调用,如果含有析构函数,则会在销毁对象时调用。构造函数的名字和类名相同,析构函数和构造函数的名字相同,但析构函数要在名字前加一个波浪号~。以往,当退出含有该对象的成员时,析构函数将自动释放这个对象所占用的内存空间。
1、构造函数的概念及使用
构造函数是在创建给定类型的对象时执行的类方法。构造函数具有与类相同的名称,它通常初始化新对象的数据成员。
不带参数的构造函数称为“默认构造函数”。无论何时,只要使用new运算符实例化对象,并且不为 new提供任何参数,就会调用默认构造函数。
//构造函数
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Test9_2
{
class Program
{
public int x = 3; //定义int型变量,作为加数
public int y = 5; //定义int型变量,作为被加数
public int z = 0; //定义int型变量,记录加法运算的和
public Program()
{
z = x + y; //在构造函数中为和赋值
}
static void Main(string[] args)
{
if (args is null) //解除IDE0060
{
throw new ArgumentNullException(nameof(args));
}
Program program = new(); //使用构造函数实例化Program对象
Console.WriteLine("结果:" + program.z);//使用实例化的Program对象输出加法运算的和
Console.Read();
}
}
}
/*运行结果:
结果:8 */
2、终结器的概念及使用
终结器(以前称为析构器)用于在垃圾回收器收集类实例时执行任何必要的最终清理操作。
终结器隐式调用对象基类上的 Finalize。 因此,对终结器的调用会隐式转换为以下代码:
protected override void Finalize()
{
try
{
// Cleanup statements...
}
finally
{
base.Finalize();
}
}
这种设计意味着,对继承链(从派生程度最高到派生程度最低)中的所有实例以递归方式调用 Finalize 方法。
不应使用空终结器。不必要的终结器会导致不必要的性能损失。
应尽可能避免终结器,因为跟踪对象生存期会产生额外的性能系统开销。 垃圾回收器在收集对象之前运行终结器。
如果调试需要终结器,请将整个终结器置于 #if DEBUG / #endif 指令中。
public class Class3
{
#if DEBUG
// Violation will not occur because the finalizer will exist and
// contain code when the DEBUG directive is present. When the
// DEBUG directive is not present, the finalizer will not exist,
// and therefore not be empty.
~Class3()
{ Debug.Fail("Finalizer called!"); }
#endif
}
对于终结器是否在应用程序终止过程中运行,这特定于每个 .NET 的实现。 .NET 5(包括 .NET Core)及更高版本不会在应用程序终止过程中调用终结器。
//析构函数
//CA1821:移除空终结器或需要#if DEBUG/#endif
//.NET Framework:输出显示当应用程序终止时,这三个类的终结器将按照派生程度最高到最低的顺序自动进行调用。
//.NET 5(包括 .NET Core)或更高版本:没有输出,因为在应用程序终止时,此 .NET 的实现不调用终结器。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Test9_3
{
class Program
{
public Program()
{
Console.WriteLine("我是构造函数");
}
#if DEBUG //.NET5以上即使采用#if DEBUG /#endif也是徒劳的
~Program() //析构函数
{
Console.WriteLine("析构函数自动调用"); //输出一个字符串
}
#endif
static void Main(string[] args)
{
if (args is null) //解除IDE0060
{
throw new ArgumentNullException(nameof(args));
}
Program program = new(); //实例化Program对象
}
}
}
/*运行结果:
我是构造函数 */
3、总结
这篇关于构造函数和终结器的总结,最有价值的地方是关于终结器的新说法。以往在.NET5以下如果在类中定义了终结器,会在应用程序终止过程中调用终结器。但在.NET5以上即使在类中定义了终结器,即使将整个终结器置于 #if DEBUG / #endif 指令中,都不会在应用程序终止过程中调用终结器。