昨天我们团队的一位同学问到我关于using关键字作为定义范围使用自动释放对象是如何工作的问题.
其实using关键字作为范围定义使用,自动完成释放工作完全是一种语法层面的简化.
其实using关键字作为范围定义使用,自动完成释放工作完全是一种语法层面的简化.
首先我们按照标准using作为范围使用的方法编写一个程序;
public class A : IDisposable
{
/// <summary>
/// 成员
/// </summary>
private int i;
/// <summary>
/// 构造函数
/// </summary>
public A()
{
i = 0;
}
/// <summary>
/// 函数方法
/// </summary>
/// <returns></returns>
public int GetValue()
{
return i;
}
/// <summary>
/// 销毁函数
/// </summary>
public void Dispose()
{
//销毁操作
}
}
class Demo
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
static void Main(string[] args)
{
using(A a = new A())
{
Console.WriteLine(a.GetValue());
}
}
}
public class A : IDisposable
{
/// <summary>
/// 成员
/// </summary>
private int i;
/// <summary>
/// 构造函数
/// </summary>
public A()
{
i = 0;
}
/// <summary>
/// 函数方法
/// </summary>
/// <returns></returns>
public int GetValue()
{
return i;
}
/// <summary>
/// 销毁函数
/// </summary>
public void Dispose()
{
//销毁操作
}
}
class Demo
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
static void Main(string[] args)
{
using(A a = new A())
{
Console.WriteLine(a.GetValue());
}
}
}
其实这里关于使用using作为对象范围要求函数实现具有IDisposable接口Dispose函数.
为什么需要这样呢?可以肯定在这个过程中必定自动调用了Dispose函数,居然如何实现的呢?
我们使用ildasm反汇编IL看一下上面这个程序的中间代码:
.try
{
IL_0006: ldloc.0
IL_0007: callvirt instance int32 ConsoleApplication1.A::GetValue()
IL_000c: call void [mscorlib]System.Console::WriteLine(int32)
IL_0011: leave.s IL_001d
} // end .try
finally
{
IL_0013: ldloc.0
IL_0014: brfalse.s IL_001c
IL_0016: ldloc.0
IL_0017: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_001c: endfinally
} // end handler
我们使用ildasm反汇编IL看一下上面这个程序的中间代码:
.try
{
IL_0006: ldloc.0
IL_0007: callvirt instance int32 ConsoleApplication1.A::GetValue()
IL_000c: call void [mscorlib]System.Console::WriteLine(int32)
IL_0011: leave.s IL_001d
} // end .try
finally
{
IL_0013: ldloc.0
IL_0014: brfalse.s IL_001c
IL_0016: ldloc.0
IL_0017: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_001c: endfinally
} // end handler
很奇怪,为什么出现了try和finally结构呢?
按照这个思路,我重新写了一段代码实现上面的功能.
static void Main(string[] args)
{
A a = new A();
try
{
Console.WriteLine(a.GetValue());
}
finally
{
a.Dispose();
}
}
{
A a = new A();
try
{
Console.WriteLine(a.GetValue());
}
finally
{
a.Dispose();
}
}
再去用ildasm工具做反汇编,居然和使用using控制范围结果获得同样的IL.
其实这样也就可以结实为什么必须实现Dispose接口的原因了,因为using范围对象其实本质是对try..finally自动释放的一种语法简化.