In the CLI, a method may define a range of CIL instructions that are said to be protected. This is called the "try block." It can then associate one or more handlers with that try block. If an exception occurs during execution anywhere within the try block, an exception object is created that describes the problem. The CIL then takes over, transferring control from the point at which the exception was thrown, to the block of code that is willing to handle that exception. See Partition I.
The next few sections expand upon this simple description, by describing the five kinds of code blocks that take part in exception processing: try, catch, filter, finally, and fault. (Note that there are restrictions upon how many, and what kinds of <sehClause> a given <tryBlock> may have; see Partition I, section 12.4.2 for details.) The remaining syntax items are described in detail below; they are collected here for reference.
18.1 Protected BlocksA try, or protected, or guarded, block is declared with the .try directive.
In the first, the protected block is delimited by two labels. The first label is the first instruction to be protected, while the second label is the instruction just beyond the last one to be protected. Both labels shall be defined prior to this point. The second uses a scope block (see Partition II, section 14.4.4) after the .try directive the instructions within that scope are the ones to be protected. 18.2 Handler Blocks
In the first syntax, the labels enclose the instructions of the handler block, the first label being the first instruction of the handler while the second is the instruction immediately after the handler. Alternatively, the handler block is just a scope block.
18.3 atch [Blocks]A catch block is declared using the catch keyword. This specifies the type of exception object the clause is designed to handle, and the handler code itself.
Example (informative): .try { ... // protected instructions leave exitSEH // normal exit } catch [mscorlib]System.FormatException { ... // handle the exception pop // pop the exception object leave exitSEH // leave catch handler } exitSEH: // continue here 18.4 Filter [Blocks]A filter block is declared using the filter keyword.
The filter code begins at the specified label and ends at the first instruction of the handler block. (Note that the CLI demands that the filter block shall immediately precede, within the CIL stream, its corresponding handler block.) Example (informative): .method public static void m () { .try { ... // protected instructions leave exitSEH // normal exit } filter { ... // decide whether to handle pop // pop exception object ldc.i4.1 // EXCEPTION_EXECUTE_HANDLER endfilter // return answer to CLI } { ... // handle the exception pop // pop the exception object leave exitSEH // leave filter handler } exitSEH: ... } 18.5 Finally [Blocks]A finally block is declared using the finally keyword. This specifies the handler code, with this grammar:
The last possible CIL instruction that can be executed in a finally handler shall be endfinally. Example (informative): .try { ... // protected instructions leave exitTry // shall use leave } finally { ... // finally handler endfinally } exitTry: // back to normal 18.6 Fault Handler [Blocks]A fault block is declared using the fault keyword. This specifies the handler code, with this grammar:
The last possible CIL instruction that can be executed in a fault handler shall be endfault. Example (informative): .method public static void m() { startTry: ... // protected instructions leave exitSEH // shall use leave endTry: startFault: ... // fault handler instructions endfault endFault: .try startTry to endTry fault handler startFault to endFault exitSEH: // back to normal } |