zoukankan      html  css  js  c++  java
  • 被淡忘的c#析构函数

    析构函数在C#中已经很少使用了,以至于很多人已经把它淡忘了,虽然用处不大,研究一下也无防。(原文:http://bbs.csdn.net/topics/300178463
    一. 析构函数的特征:
    析构函数只能存在于类中,而不能存在于结构中;析构函数不能有任何修饰符,包括访问控制修饰符,静态修饰符,抽象修饰符,虚拟修饰符等都不能有;析构函数没有参数,这就意味着不能有任何重载。
    二. 析构函数的调用时机:
    析构函数会在对象被垃圾收集器回收时调用,但垃圾收集器有个特点,它是懒惰的, 它并不会在变量出了作用域和生命期后立即回收,而是在它认为适当的时候才回收,一般是内存紧张的时候。如:

     
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
        class MainForm : Form
        {
            Button btn = new Button();
            public MainForm()
            {
                btn.Click += btn_Click;
            }
            void btn_Click(object sender, EventArgs e)
            {
                Demo de = new Demo();
            }
        }
        class Demo
        {
            ~Demo()
            {
                MessageBox.Show("析构函数被调用");
            }
    }

    在方法btn_Click返回后,de就应该被终结了,可是它的析构函数并没有被调用,说明垃圾收集器并没有将其回收;而当你关闭窗体的时候,析构函数被执行了,说明在程序结束的时候,垃圾收集器才不情愿地被迫将其回收(^-^)。 当然,我们可以调用GC.Collect()来强制回收:

     
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
        class MainForm : Form
        {
            Button btn1 = new Button();
            Button btn2 = new Button();
            public MainForm()
            {
                btn1.Click += btn1_Click;
                btn2.Click += btn2_Click;
                btn2.Top = 40;
                this.Controls.Add(btn1);
                this.Controls.Add(btn2);
            }
            void btn1_Click(object sender, EventArgs e)
            {
                Demo de1 = new Demo();
                de1 = null;
                Demo de2 = new Demo();
                new Demo();
                GC.Collect();
            }
            void btn2_Click(object sender, EventArgs e)
            {
                GC.Collect();
            }
     
        }
        class Demo
        {
            ~Demo()
            {
                MessageBox.Show("析构函数被调用");
            }
    }

    单击btn1的时候,de1和new Demo()被终结,析构函数被调用。 而de2尚未出生命期,所以虽然调用了GC.Collect方法,也不会回收;当btn1_Click返回时,de2出了生命期,但由于垃圾收集器的懒惰性,所以仍然没被回收;直到单击btn2调用GC.Collect方法,de2才被回收,其析构函数才被调用。
    有一种办法能够阻止析构函数的调用,那就是实现IDisposable接口,这个接口定义了一个唯一的方法:Dispose()。 这样做之所以能阻止析构函数,是因为内部通常调用了GC.SuppressFinalize()方法,换句话说,如果你闲得无聊,完全可以实现这个接口,却不去调用GC.SuppressFinalize方法(^-^),这样的话就没任何意义了,因为阻止不了析构函数:

    1
    2
    3
    4
    5
    6
    7
    8
           void btn1_Click(object sender, EventArgs e)
            {
                Demo de1 = new Demo();
                Demo de2 = new Demo();
                GC.SuppressFinalize(de1);
                de1 = null;
                GC.Collect();
            }

    现在de1的析构函数就不会被调用了。
    三. 析构函数的本质:
    析构函数本质上是一个方法,其形式如下:

    1
    2
    3
            protected void Finalize()
            {
            }

    通常我们认为析构函数只能由系统调用,而不能由程序员自己去调用,其实这不完全正确,析构函数也可以被显式调用,毕竟它也只是一个方法:

    1
    2
    Demo de = new Demo();
    typeof(Demo).GetMethod("Finalize",BindingFlags.Instance|BindingFlags.NonPublic).Invoke(de, null);
  • 相关阅读:
    图片尺寸批量resize的matlab并行代码
    Java使用QRCode.jar生成与解析二维码
    MySQL求两表的差集(非交集)
    sql笔记
    Oracle创建表空间创建用户授权
    身份证前6位地址码+码表+MySQL
    Jenkins时区设置为北京时间
    Oracle 使用MERGE INTO 语句 一条语句搞定新增编辑
    Oracle dd-m月-yy转yyyy-mm-dd
    docker 使用笔记
  • 原文地址:https://www.cnblogs.com/mzws/p/3578800.html
Copyright © 2011-2022 走看看