析构函数在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方法(^-^),这样的话就没任何意义了,由于阻止不了析构函数:this
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的析构函数就不会被调用了。
三. 析构函数的本质:
析构函数本质上是一个方法,其形式以下:spa
1
2
3
|
protected
void
Finalize()
{
}
|
一般咱们认为析构函数只能由系统调用,而不能由程序员本身去调用,其实这不彻底正确,析构函数也能够被显式调用,毕竟它也只是一个方法:.net
1
2
|
Demo de =
new
Demo();
typeof
(Demo).GetMethod(
"Finalize"
,BindingFlags.Instance|BindingFlags.NonPublic).Invoke(de,
null
);
|