Exception blocks
Protected regions use the ILAsm block form. Each boundary is its own line.
il[1]> .locals init (string m) locals: 0:string mil[1]> .try { try ┊ []il[1]> ldstr "boom" ┊ [string]il[1]> newobj instance void InvalidOperationException::.ctor(string) ┊ [InvalidOperationException]il[1]> throw ┊ []il[1]> } catch InvalidOperationException { catch InvalidOperationException ┊ [InvalidOperationException]il[1]> callvirt instance string Exception::get_Message() ┊ [string]il[1]> stloc m ┊ []il[1]> leave DONE ┊ []il[1]> } finally { finally ┊ []il[1]> ldstr "finally ran" ┊ [string]il[1]> call void Console::WriteLine(string) ┊ []il[1]> } end of protected region ┊ unreachableil[1]> DONE: ldloc m ┊ [string]il[1]> retfinally ran = "boom" : stringThe boundaries are:
| Line | Meaning |
|---|---|
.try { |
Opens a protected region. |
} catch T { |
A handler for exceptions of type T. The exception is on the stack when it starts. |
} filter { |
A filter expression. It sees the exception and leaves an int32 for endfilter to consume. |
} handler { |
The handler that runs when the filter returned non-zero. |
} finally { |
Runs when control leaves the protected region. Must be the last handler. |
} fault { |
Runs only on the exception path. Must be the last handler. |
} |
Closes the region. |
Leave a region with leave, not ret or br. The stack is empty at every boundary except the
start of a catch, filter, or filter handler, where it holds the exception.
A filter cannot contain another .try. If the filter throws, exception search continues with the next clause.
A filter
Section titled “A filter”il[2]> .locals init (int32 n) locals: 0:string m, 1:int32 nil[2]> .try { try ┊ []il[2]> ldc.i4 1 ┊ [int32]il[2]> ldc.i4 0 ┊ [int32, int32] ◂ topil[2]> div ┊ [int32]il[2]> stloc n ┊ []il[2]> leave END ┊ []il[2]> } filter { filter (end it with endfilter, then } handler {) ┊ [object]il[2]> isinst DivideByZeroException ┊ [DivideByZeroException]il[2]> ldnull ┊ [DivideByZeroException, null] ◂ topil[2]> cgt.un ┊ [int32]il[2]> endfilter ┊ []il[2]> } handler { filter handler ┊ [object]il[2]> pop ┊ []il[2]> ldc.i4 42 ┊ [int32]il[2]> stloc n ┊ []il[2]> leave END ┊ []il[2]> } end of protected region ┊ unreachableil[2]> END: ldloc n ┊ [int32]il[2]> ret = 42 : int32Regions nest: a .try { inside a handler opens an inner region.
Exact ranges
Section titled “Exact ranges”The label form preserves exception layouts from imported methods, including noncontiguous handlers:
.try START to END catch Exception handler CATCH to DONE.try START to END filter FILTER handler HANDLER to DONE.try START to END finally handler FINALLY to DONE.try START to END fault handler FAULT to DONEEach line declares one clause. Start labels are inclusive and end labels are exclusive; an end label may
name the end of the method without adding an instruction. Clauses retain declaration order because it
can affect exception dispatch. A filter ends with endfilter, and a finally or fault ends with endfinally.
Range clauses can also describe a catch inside a surrounding structured finally block.
.edit supplies these ranges automatically. See Editing and comparing methods.