析构函数

https://blog.csdn.net/leonwei/article/details/52471026

GC回收机制

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GCHandle
{
    class Program
    {
        
         static void Main(string[] args)
        {
          
            test1();
            Console.ReadKey();

        }
        static void test1()
        {
            Son son = new Son();
            son.Age = 32;
            Console.WriteLine(son.Age);
            son = null;
            //GC.Collect();
        }
       
        public static void write(string connStr)
        {

            FileStream fs = new FileStream("GCTest.txt", FileMode.Append);
            StreamWriter sw = new StreamWriter(fs);
            try
            {
                sw.WriteLine(connStr);
                sw.Flush();
                sw.Close();
                fs.Close();
            }
            catch (IOException e)
            {
                sw.Flush();
                sw.Close();
                fs.Close();
            }
        }
    }

   
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GCHandle
{
    public class Person
    {
        int count = 0;
        public string Name { get; set; }
        public int Age { get; set; }
        public int Height { get; set; }
        public Person()
        {

        }
        public Person(string name, int age, int height)
        {
            this.Age = age;
        }
        //析构函数
        ~Person()
        {
            count++;
            Program.write($"Person调用了析构函数{count}次");
            //Cleaning up code goes here
            Console.WriteLine($"Person调用了析构函数{count}次");
        }
    }
    public class Father : Person
    {
        int count = 0;
        public Father()
        {

        }
        public Father(string name, int age, int height)
        {
            this.Age = age;
        }
        //析构函数
        ~Father()
        {
            count++;
            Program.write($"Father调用了析构函数{count}次");
            //Cleaning up code goes here
            Console.WriteLine($"Father调用了析构函数{count}次");
        }
    }

    public class Son : Father
    {
        int count = 0;
        public Son()
        {

        }
        public Son(string name, int age, int height)
        {
            this.Age = age;
        }
        //析构函数
        ~Son()
        {
            count++;
            Program.write($"Son调用了析构函数{count}次");
            //Cleaning up code goes here
            Console.WriteLine($"Son调用了析构函数{count}次");
        }
    }
}

输出结果:

32

可以发现当son=null,析构函数并没有执行,奇怪的是,程序退出后,应该会调用析构函数,但是,并没有在文件看到写入的值,这点我再。。。。。。思考思考。

如果一旦你使用完对象你就想调用析构函数,你该怎么做?有两个方法:1.启用GC.Collect,但在大多数情况下,这应该避免因为它会导致性能问题。2.实现IDisposable的Dispose方法,Dispose是用于释放所有资源对象,包括托管的和非托管的。

1.GC.Collect,输出结果:

32
Son调用了析构函数1次
Father调用了析构函数1次
Person调用了析构函数1次

 并且在文件中也写入了调用析构函数的信息,子类调用析构函数,父类也会调用析构函数

Son调用了析构函数1次
Father调用了析构函数1次
Person调用了析构函数1次

首先,对于垃圾回收而言,在C#中,托管资源的垃圾回收是通过CLR的Garbage Collection来实现的,Garbage Collection会调用堆栈上对象的析构函数完成对象的释放工作;而对于一些非托管

资源,比如数据库链接对象等,需要实现IDisposable接口进行手动的垃圾回收。

2.实现IDisposable的Dispose方法,在.NET的对象中实际上有两个用于释放资源的函数:Dispose和Finalize,这里先介绍Dispose,Dispose是用于释放所有资源,包括托管的和非托管的。当我

们自定义的类及其业务逻辑中引用某些托管和非托管资源,就需要实现IDisposable接口,实现对这些资源对象的垃圾回收。

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GCHandle
{
    public class Person : IDisposable
    {
        int count = 0;
        public string Name { get; set; }
        public int Age { get; set; }
        public int Height { get; set; }

        public Person()
        {
            Console.WriteLine($"Person构造函数");
        }
        public Person(string name, int age, int height)
        {
            this.Age = age;
        }
        //析构函数
        ~Person()
        {
            count++;
            Dispose(false);// 清空你调用的非托管对象不是清空自己
            Program.write($"Person调用了析构函数{count}次");
            Console.WriteLine($"Person调用了析构函数{count}次");
        }

        private bool _isDisposed = false;

        public void Dispose()
        {
            // 在这里清空所有你调用的托管对象。
this.Dispose(true); // 该方法告诉垃圾回收器有一个类不再需要调用其析构函数了 // 因为Dispose()方法已经完成了所有需要清理的工作,所以析构函数不需要做任何工作 // 调用SuppressFinalize()方法就意味着垃圾会后期认为这个对象根本没有析构函数 System.GC.SuppressFinalize(this); } //另外,把Dispose(bool disposing)方法设置为protected virtual的原因是希望有子类可以一起参与到垃圾回收逻辑的设计,而且还不会影响到基类。 protected virtual void Dispose(bool disposing) { // 使用这种结构的原因是,当一个对象被释放时,它所占用的资源必须被全部释放 // 释放既可以通过代码实现,也可以通过DotNet垃圾回收机制来完成 // 因为垃圾回收机制只能释放托管的资源,因此非托管资源必须通过代码进行释放 // 首先需要判断该对象有没有被释放,在没有被释放的情况下才进行释放 if (!this._isDisposed) { // 判断是否执行托管资源的释放 // 垃圾回收机制认为每个类所占有的资源由类本身进行释放, // 如果一个类中包含另一个类对象的引用,该引用对象所占有的资源的释放由该引用对象自身来保证 // 因此,正常情况下都是在析构函数中调用 Dispose(false) if (disposing) { // 在这里清空所有你调用的托管对象。
Dispose(); Console.WriteLine("清空托管对象"); } else { // 清空你调用的非托管对象 Console.WriteLine("清空非托管对象"); }
                 _isDisposed = true; } } } }
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GCHandle
{
    class Program
    {

         static void Main(string[] args)
        {
            test1();
            Console.ReadKey();
        }
        static void test1()
        {
            Person p = new Person();
            p.Age = 32;
            Console.WriteLine(p.Age);
            p = null;
        }
       
        public static void write(string connStr)
        {
            FileStream fs = new FileStream("GCTest.txt", FileMode.Append);
            StreamWriter sw = new StreamWriter(fs);
            try
            {
                sw.WriteLine(connStr);
                sw.Flush();
                sw.Close();
                fs.Close();
            }
            catch (IOException e)
            {
                sw.Flush();
                sw.Close();
                fs.Close();
            }
        }
    }
}

 注意:

析构函数用于析构类的实例。

1)         不能在结构中定义析构函数。只能对类使用析构函数。

2)         一个类只能有一个析构函数。

3)         无法继承或重载析构函数。

4)         无法调用析构函数。它们是被自动调用的。

5)         析构函数既没有修饰符,也没有参数。

关于Finalize的介绍,可以看下这篇博文【C#】GC和析构函数(Finalize 方法)

 

posted @ 2021-04-02 10:37  WellMandala  阅读(240)  评论(0编辑  收藏  举报