public class ParentClass
{
public ParentClass()
{
Console.WriteLine("ParentClass构造函数");
}
public void DoSomeThing()
{
Console.WriteLine("ParentClass做点什么DoSomeThing()");
}
~ParentClass()
{
Console.WriteLine("ParentClass析构函数");
}
}
internal class Program
{
static void Main(string[] args)
{
ReadInfo();
Console.ReadKey();
}
private static void ReadInfo()
{
Console.WriteLine("ReadInfo开始调用............");
ParentClass parentClass = new ParentClass();
parentClass.DoSomeThing();
Console.WriteLine("ReadInfo结束调用............");
}
}
ReadInfo开始调用............
ParentClass构造函数
ParentClass做点什么DoSomeThing()
ReadInfo结束调用............
在 C# 中,构造函数就是与类(或结构体)具有相同名称的成员函数,它在类中的地位比较特殊,
在 C# 中,构造函数是一种特殊类型的方法,用于初始化类的新实例。它的主要任务是为对象的成员变量赋初值、执行一些初始化操作或者为对象分配必要的资源。
构造函数的名称与类名相同,没有返回类型(甚至不能使用 void
),并且不能被显式地调用。它在创建类的实例时由 .NET 运行时自动调用。
构造函数有两种主要类型:
class MyClass
{
// 默认构造函数,无参构造函数
public MyClass()
{
// 初始化操作
}
}
class Person
{
public string Name { get; set; }
public int Age { get; set; }
// 自定义构造函数,有参构造函数
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
当你创建一个类的新实例时,会自动调用合适的构造函数来完成对象的初始化。例如:
Person person1 = new Person("Alice", 30); // 使用自定义构造函数
Person person2 = new Person(); // 使用默认构造函数
需要注意的是,如果你自定义了构造函数,则默认构造函数不再自动生成。如果你希望保留默认构造函数,同时定义自己的构造函数,需要显式地提供默认构造函数。例如:
class MyClass
{
public MyClass()
{
// 默认构造函数
}
public MyClass(int value)
{
// 自定义构造函数
}
}
构造函数在类的实例化过程中扮演着非常重要的角色,确保对象在创建时处于正确的状态。
在 C# 中,析构函数又称为 “Finalize” 方法。它是一种特殊类型的方法,用于在对象被垃圾回收之前执行一些清理工作。在 C# 中,程序员通常不需要手动编写析构函数,因为 .NET 的垃圾回收机制会自动处理内存管理和资源清理。
在需要手动管理非托管资源(例如文件、数据库连接、网络资源等)的情况下,可以使用析构函数来确保这些资源在对象被回收时得到释放。但是,现在推荐使用更现代的手段如实现 IDisposable
接口,使用 using
语句块,或使用 Dispose
方法来进行资源清理。这些方法提供了更明确和可控的资源管理方式。
如果你还是想了解如何编写析构函数,下面是一个示例:
using System;
class MyClass
{
// 析构函数
~MyClass()
{
// 执行资源清理的代码
// 例如关闭文件、释放非托管资源等
Console.WriteLine("Destructor is called. Cleaning up resources.");
}
}
class Program
{
static void Main()
{
// 创建一个对象
MyClass obj = new MyClass();
// 程序运行到此结束时,对象可能还未被回收,所以析构函数可能会在程序结束之后被调用。
}
}
值得注意的是,析构函数的调用时间是由垃圾回收器决定的,所以无法确切控制它何时被调用。这也是为什么推荐使用 IDisposable
接口和 Dispose
方法,以便在资源不再需要时立即进行释放和清理。
回到我们一开始的案例中,我们在ParentClass
类中编写了构造函数ParentClass()
和析构函数~ParentClass()
,但是在最后的输出中,我们看到只有构造函数被执行,但是析构函数并没有被执行。
~ParentClass()
{
Console.WriteLine("ParentClass析构函数");
}
到此出,问题来了,不是说析构函数程序员通常不需要手动编写析构函数,因为 .NET 的垃圾回收机制会自动处理内存管理和资源清理。
,但是为什么析构函数并没有被执行呢?这是以为只有在触发垃圾回收时,才会调用析构函数,基于此我们来改一下Main
函数,使其主动调用一下GC。
internal class Program
{
static void Main(string[] args)
{
ReadInfo();
Console.WriteLine("调用GC............");
GC.Collect();
Console.ReadKey();
}
private static void ReadInfo()
{
Console.WriteLine("ReadInfo开始调用............");
ParentClass parentClass = new ParentClass();
parentClass.DoSomeThing();
Console.WriteLine("ReadInfo结束调用............");
}
}
ReadInfo开始调用............
ParentClass构造函数
ParentClass做点什么DoSomeThing()
ReadInfo结束调用............
调用GC............
ParentClass析构函数
这个时候我们发现GC被调用,只是这个时候GC是主动调用的
。
static void Main(string[] args)
{
ReadInfo();
//Console.WriteLine("调用GC............");
//GC.Collect();
List list = new List();
for (int i = 0; i < 100000000; i++)
{
list.Add($"内存调用{ i }");
}
//ReadInfo();
Console.ReadKey();
}
private static void ReadInfo()
{
Console.WriteLine("ReadInfo开始调用............");
ParentClass parentClass = new ParentClass();
parentClass.DoSomeThing();
//List list = new List();
//for (int i = 0; i < 100000000; i++)
//{
// list.Add($"内存调用{ i }");
//}
Console.WriteLine("ReadInfo结束调用............");
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FTdSsa1g-1690855974476)(GC发生调用.png)]
以下这个则不会触发调用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ckCtIIR0-1690855974478)(GC没有调用.png)]
static void Main(string[] args)
{
ReadInfo();
//Console.WriteLine("调用GC............");
//GC.Collect();
//ReadInfo();
Console.ReadKey();
}
private static void ReadInfo()
{
Console.WriteLine("ReadInfo开始调用............");
ParentClass parentClass = new ParentClass();
parentClass.DoSomeThing();
parentClass = null;
List list = new List();
for (int i = 0; i < 100000000; i++)
{
list.Add($"内存调用{ i }");
}
Console.WriteLine("ReadInfo结束调用............");
}
internal class Program
{
static void Main(string[] args)
{
ReadInfo();
Console.ReadKey();
}
private static void ReadInfo()
{
Console.WriteLine("ReadInfo开始调用............");
ParentClass parentClass = new ParentClass();
parentClass.DoSomeThing();
parentClass = new ParentClass();
parentClass.DoSomeThing();
Console.WriteLine("ReadInfo结束调用............");
}
}
ReadInfo开始调用............
ParentClass构造函数
ParentClass做点什么DoSomeThing()
ParentClass构造函数
ParentClass做点什么DoSomeThing()
ReadInfo结束调用............
ChildClass
继承了ParentClass
代码如下:
public class ParentClass
{
public ParentClass()
{
Console.WriteLine("ParentClass构造函数");
}
public void DoSomeThing()
{
Console.WriteLine("ParentClass做点什么DoSomeThing()");
}
~ParentClass()
{
Console.WriteLine("ParentClass析构函数");
}
}
public class ChildClass: ParentClass
{
public ChildClass()
{
Console.WriteLine("ChildClass构造函数");
}
~ChildClass()
{
Console.WriteLine("ChildClass析构函数");
}
}
internal class Program
{
static void Main(string[] args)
{
ReadInfo();
Console.ReadKey();
}
private static void ReadInfo()
{
Console.WriteLine("ReadInfo开始调用............");
ChildClass childClass=new ChildClass();
childClass.DoSomeThing();
Console.WriteLine("ReadInfo结束调用............");
}
}
揭晓答案,答案是A:先调用父类,再调用子类
ReadInfo开始调用............
ParentClass构造函数
ChildClass构造函数
ParentClass做点什么DoSomeThing()
ReadInfo结束调用............
GC.Collect();
时,会先调用子类再调用父类。static void Main(string[] args)
{
ReadInfo();
Console.WriteLine("调用GC............");
GC.Collect();
Console.ReadKey();
}
ReadInfo开始调用............
ParentClass构造函数
ChildClass构造函数
ParentClass做点什么DoSomeThing()
ReadInfo结束调用............
调用GC............
ChildClass析构函数
ParentClass析构函数
ParentClass
父类上再增加一层类。public class BaseClass
{
public BaseClass()
{
Console.WriteLine("BaseClass构造函数");
}
public void DoSomeThing()
{
Console.WriteLine("BaseClass做点什么DoSomeThing()");
}
~BaseClass()
{
Console.WriteLine("BaseClass析构函数");
}
}
public class ParentClass: BaseClass
{
public ParentClass()
{
Console.WriteLine("ParentClass构造函数");
}
public new void DoSomeThing()
{
Console.WriteLine("ParentClass做点什么DoSomeThing()");
}
~ParentClass()
{
Console.WriteLine("ParentClass析构函数");
}
}
public class ChildClass: ParentClass
{
public ChildClass()
{
Console.WriteLine("ChildClass构造函数");
}
~ChildClass()
{
Console.WriteLine("ChildClass析构函数");
}
}
internal class Program
{
static void Main(string[] args)
{
ReadInfo();
Console.WriteLine("调用GC............");
GC.Collect();
Console.ReadKey();
}
private static void ReadInfo()
{
Console.WriteLine("ReadInfo开始调用............");
ChildClass childClass=new ChildClass();
childClass.DoSomeThing();
Console.WriteLine("ReadInfo结束调用............");
}
}
ReadInfo开始调用............
BaseClass构造函数
ParentClass构造函数
ChildClass构造函数
ParentClass做点什么DoSomeThing()
ReadInfo结束调用............
调用GC............
ChildClass析构函数
ParentClass析构函数
BaseClass析构函数
IDispose
internal class Program
{
static void Main(string[] args)
{
UsingReadInfo();
Console.ReadKey();
}
private static void UsingReadInfo()
{
Console.WriteLine("UsingReadInfo开始调用............");
using (ChildClass childClass = new ChildClass())
{
childClass.DoSomeThing();
}
Console.WriteLine("UsingReadInfo结束调用............");
}
private static void ReadInfo()
{
Console.WriteLine("ReadInfo开始调用............");
ChildClass childClass=new ChildClass();
childClass.DoSomeThing();
Console.WriteLine("ReadInfo结束调用............");
}
}
public class BaseClass:IDisposable
{
public BaseClass()
{
Console.WriteLine("BaseClass构造函数");
}
public void DoSomeThing()
{
Console.WriteLine("BaseClass做点什么DoSomeThing()");
}
~BaseClass()
{
Console.WriteLine("BaseClass析构函数");
}
public void Dispose()
{
Console.WriteLine("BaseClass调用Dispose");
}
}
public class ParentClass: BaseClass, IDisposable
{
public ParentClass()
{
Console.WriteLine("ParentClass构造函数");
}
public new void DoSomeThing()
{
Console.WriteLine("ParentClass做点什么DoSomeThing()");
}
~ParentClass()
{
Console.WriteLine("ParentClass析构函数");
}
public void Dispose()
{
Console.WriteLine("ParentClass调用Dispose");
}
}
public class ChildClass: ParentClass, IDisposable
{
public ChildClass()
{
Console.WriteLine("ChildClass构造函数");
}
~ChildClass()
{
Console.WriteLine("ChildClass析构函数");
}
public void Dispose()
{
Console.WriteLine("ChildClass调用Dispose");
}
}
UsingReadInfo开始调用............
BaseClass构造函数
ParentClass构造函数
ChildClass构造函数
ParentClass做点什么DoSomeThing()
ChildClass调用Dispose
UsingReadInfo结束调用............
public class BaseClass:IDisposable
{
public virtual void Dispose()
{
Console.WriteLine("BaseClass调用Dispose");
}
}
public class ParentClass: BaseClass, IDisposable
{
public override void Dispose()
{
base.Dispose();
Console.WriteLine("ParentClass调用Dispose");
}
}
public class ChildClass: ParentClass, IDisposable
{
public override void Dispose()
{
base.Dispose();
Console.WriteLine("ChildClass调用Dispose");
}
}
UsingReadInfo开始调用............
BaseClass构造函数
ParentClass构造函数
ChildClass构造函数
ParentClass做点什么DoSomeThing()
BaseClass调用Dispose
ParentClass调用Dispose
ChildClass调用Dispose
UsingReadInfo结束调用............
好久没有一气呵成的写C#代码了 好怀恋!!!