本文通过一个简单的示例来说明在IL中进行异常处理时要注意的关键点。
我们来看一个包含try...catch...finally的示例:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->
public
void
TestEF()
{
TransactionScopeFactoryfactory
=
new
TransactionScopeFactory(
null
);
TransactionScopescope
=
factory.NewTransactionScope(
false
);
try
{
scope.Commit();
}
catch
(Exceptionee)
{
string
msg
=
ee.Message;
}
finally
{
scope.Dispose();
}
}
这段代码实际上与使用using是等价的:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->
public
void
TestEF()
{
TransactionScopeFactoryfactory
=
new
TransactionScopeFactory(
null
);
using
(TransactionScopescope
=
factory.NewTransactionScope(
false
))
{
try
{
scope.Commit();
}
catch
(Exceptionee)
{
string
msg
=
ee.Message;
}
}
}
它们对应的IL代码如下所示:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->
.method
public
hidebysiginstance
void
TestEF()cilmanaged
{
.maxstack
2
.localsinit(
[
0
]
class
[DataRabbit.Application]DataRabbit.Application.TransactionScopeFactoryfactory,
[
1
]
class
[DataRabbit.Application]DataRabbit.Application.TransactionScopescope,
[
2
]
class
[mscorlib]System.Exceptionee,
[
3
]
string
msg)
L_0000:nop
L_0001:ldnull
L_0002:newobjinstance
void
[DataRabbit.Application]DataRabbit.Application.TransactionScopeFactory::.ctor(
class
[DataRabbit]DataRabbit.DataConfiguration)
L_0007:stloc.
0
L_0008:ldloc.
0
L_0009:ldc.i4.
0
L_000a:callvirtinstance
class
[DataRabbit.Application]DataRabbit.Application.TransactionScope[DataRabbit.Application]DataRabbit.Application.TransactionScopeFactory::NewTransactionScope(
bool
)
L_000f:stloc.
1
L_0010:nop
L_0011:ldloc.
1
L_0012:callvirtinstance
void
[DataRabbit.Application]DataRabbit.Application.TransactionScope::Commit()
L_0017:nop
L_0018:nop
L_0019:leave.sL_0027
L_001b:stloc.
2
L_001c:nop
L_001d:ldloc.
2
L_001e:callvirtinstance
string
[mscorlib]System.Exception::get_Message()
L_0023:stloc.
3
L_0024:nop
L_0025:leave.sL_0027
L_0027:nop
L_0028:leave.sL_0034
L_002a:nop
L_002b:ldloc.
1
L_002c:callvirtinstance
void
[DataRabbit.Application]DataRabbit.Application.TransactionScope::Dispose()
L_0031:nop
L_0032:nop
L_0033:endfinally
L_0034:nop
L_0035:ret
.
tryL_0010toL_001bcatch
[mscorlib]System.ExceptionhandlerL_001btoL_0027
.
tryL_0010toL_002afinally
handlerL_002atoL_0034
}
我们来剖析这段IL中的异常处理流程:
1.有最后的两句代码,我们看到:
(1)try...catch...finally 是由try...catch 和 try...finally两部分构成。
(2)try...finally 中的try块内含了catch块。
即类似这样:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->
.try
{
.
try
{
}
catch
{
}
}
finally
{
}
2.try块、catch块(catch handler)只能通过leave(或leave.s)退出。
3.finally块(finally handler)必须通过endfinally退出。
4.由于try...catch 和 try...finally两部分都需要退出try块,所以我们看到在L_0019 和 L_0028 处都有对应的leave.s指令。
5.程序中如果没有finally块,则IL中只需要处理try...catch 部分;同理,如果程序中没有catch块,则IL只需要处理try...finally部分。
6.总结起来,IL的异常处理类似这个样子:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->.try
{
.try
{
leave L1
}
catch
{
leave L1
}
leaveL2
}
finally
{
endfinally
}