Udostępnij za pośrednictwem


ILGenerator.BeginFaultBlock Method

Microsoft Silverlight will reach end of support after October 2021. Learn more.

Begins an exception fault block in the Microsoft intermediate language (MSIL) stream.

Namespace:  System.Reflection.Emit
Assembly:  mscorlib (in mscorlib.dll)

Syntax

'Declaration
Public Overridable Sub BeginFaultBlock
public virtual void BeginFaultBlock()

Exceptions

Exception Condition
NotSupportedException

The MSIL that is being generated is not currently in an exception block.

-or-

This ILGenerator belongs to a DynamicMethod.

Remarks

If the current ILGenerator is associated with a DynamicMethod object, emitting exception fault blocks is not supported.

Fault blocks behave like finally blocks, with one important difference: A fault handler is executed only when an exception occurs.

Like a finally block, a fault block does not prevent exceptions from propagating. It only provides an opportunity to execute code when an exception occurs.

The ECMA specification states that a block of code that is protected by an exception block has only one kind of handler. If you emit a fault handler in an exception block that also contains a catch handler or a finally handler, the resulting code is unverifiable. No exception is thrown when the code is emitted, but when it is compiled the just-in-time (JIT) compiler throws an InvalidProgramException. Use nested exception blocks for multiple kinds of handlers, as shown in the example.

NoteNote:

Fault blocks are not used in MSIL that is generated by Visual Basic or C#. For information about fault blocks, see the ECMA Partition I documentation. The documentation is available online; see ECMA C# and Common Language Infrastructure Standards on MSDN and Standard ECMA-335 - Common Language Infrastructure (CLI) on the Ecma International Web site.

Examples

The following example shows the difference between fault blocks and finally blocks. The example emits a fault block that runs a fault handler whenever an exception is not handled by a nested catch block, and emits a nested finally block that runs a finally handler in all cases.

The example emits a type that has a static method (Shared method in Visual Basic) named TestMethod, which has a single string parameter. TestMethod contains three exception blocks:

  • Fault block: The outermost exception block has a fault handler, which runs whenever an exception occurs in the outermost exception block.

  • Finally block: Nested inside the fault block is an exception block with a finally handler.

  • Catch block: Nested inside the finally block is an exception block with a catch handler that handles ArgumentNullException. The code that is protected by the catch block calls a helper method, Example.ThrowHelper, which throws an ArgumentNullException if its argument is nulla null reference (Nothing in Visual Basic), an ArgumentException if its argument has zero length, and no exceptions otherwise. (See the end of the code listing.)

The example uses the TypeBuilder.CreateType method to complete the dynamic type that contains TestMethod, the Type.GetMethod method to get a MethodInfo that represents TestMethod, and the Delegate.CreateDelegate(Type, MethodInfo) method overload to create a delegate that can be used to execute TestMethod. The example then invokes the delegate three times with different arguments:

  • When the string "text" is passed to TestMethod, the helper method completes normally. TestMethod displays a normal completion message, and the finally handler in the nested finally block runs, displaying another message. The fault handler in the outer fault block does not run, because no exception occurred.

  • When nulla null reference (Nothing in Visual Basic) is passed to TestMethod, the helper method throws an ArgumentNullException that is caught by the catch block. The catch handler and the finally handler run, each displaying a message. The fault handler does not run, because the exception is handled by the inner catch block, and no exception occurs in the outer fault block.

  • When an empty string, "", is passed to TestMethod, the helper method throws an ArgumentException. This exception is not caught. The finally handler runs and displays a message, and the fault handler runs and displays a message. An exception handler in the example catches the exception and displays its message.

To run this example, see Building Examples That Use a Demo Method and a TextBlock Control.

Imports System.Reflection
Imports System.Reflection.Emit

Public Class Example

   Public Shared Sub Demo(ByVal outputBlock As System.Windows.Controls.TextBlock) 

      ' Put the TextBlock in a location where the PrintHelper method can 
      ' use it.
      Example.outputBlock = outputBlock

      ' Create the dynamic assembly. In Silverlight, dynamic assemblies are
      ' transient and have only one module.
      Dim aName As New AssemblyName("EmitDemo")
      Dim ab As AssemblyBuilder = _
         AppDomain.CurrentDomain.DefineDynamicAssembly(aName, _
                                                       AssemblyBuilderAccess.Run)
      Dim mb As ModuleBuilder = ab.DefineDynamicModule("EmitDemo")

      ' Define a public type.
      Dim tt As TypeBuilder = mb.DefineType("TestType", TypeAttributes.Public)

      ' Define the Shared TestMethod method, which has one string parameter and 
      ' no return value. TestMethod passes its argument to Example.ThrowHelper,
      ' which throws different exceptions depending on the value of the argument.
      ' TestMethod handles one exception, and does not handle the other.
      Dim tm As MethodBuilder = _
         tt.DefineMethod("TestMethod", _
                         MethodAttributes.Public Or MethodAttributes.Static, _
                         Nothing, _
                         New Type() { GetType(String) })

      ' Get MethodInfo objects that represent the Example.PrintHelper method, 
      ' for writing to the TextBlock, and Example.ThrowHelper, for throwing
      ' exceptions conditionally.
      Dim printhelper As MethodInfo = GetType(Example).GetMethod("PrintHelper")
      Dim throwhelper As MethodInfo = GetType(Example).GetMethod("ThrowHelper")

      Dim il As ILGenerator = tm.GetILGenerator()

      ' Begin the outermost exception block, which includes the fault handler.
      ' The ECMA spec specifies that a protected block of code shall have only
      ' one kind of handler.
      Dim tryFault As Label = il.BeginExceptionBlock()

      ' Begin the middle exception block, which includes the finally handler.
      ' There is no rule about the order of nesting of the fault and finally
      ' handlers.
      Dim tryFinally As Label = il.BeginExceptionBlock()

      ' Begin the innermost exception block, which includes the catch handlers.
      Dim tryCatch As Label = il.BeginExceptionBlock()

      ' Load the argument string and pass it to the Shared Example.TestThrows
      ' method. The called method throws different exceptions if the argument
      ' is null or of zero length; it throws no exception otherwise.
      il.Emit(OpCodes.Ldarg_0)
      il.Emit(OpCodes.Call, throwhelper)

      ' If the call to Example.TestThrows ended normally, display a message and
      ' exit from the innermost exception block.
      il.Emit(OpCodes.Ldstr, "TestMethod: ThrowHelper ended normally.")
      il.Emit(OpCodes.Call, printhelper)
      il.Emit(OpCodes.Leave, tryCatch)

      ' Catch ArgumentNullException, display a message, and exit from the inner
      ' try/catch.
      il.BeginCatchBlock(GetType(ArgumentNullException))
      il.Emit(OpCodes.Ldstr, "TestMethod: Caught ArgumentNullException.")
      il.Emit(OpCodes.Call, printhelper)
      il.Emit(OpCodes.Leave, tryCatch)

      ' The end of the innermost exception block. 
      il.EndExceptionBlock()


      ' If the protected code ended normally, or if an exception was caught 
      ' and handled, exit from the middle exception block.
      il.Emit(OpCodes.Leave, tryFinally)

      ' The finally block displays a message.
      il.BeginFinallyBlock()
      il.Emit(OpCodes.Ldstr, "TestMethod: Finally block runs.")
      il.Emit(OpCodes.Call, printhelper)

      ' The end of the middle exception block. 
      il.EndExceptionBlock()


      ' If the protected code ended normally, or if an exception was caught 
      ' and handled, exit from the outermost exception block.
      il.Emit(OpCodes.Leave, tryFault)


      ' Begin the fault block, in the outermost exception block. The fault block
      ' displays a message. As with finally blocks, you do not use a Leave to
      ' exit from the fault block.
      il.BeginFaultBlock()
      il.Emit(OpCodes.Ldstr, "TestMethod: Fault block runs.")
      il.Emit(OpCodes.Call, printhelper)


      ' The end of the outermost exception block.
      il.EndExceptionBlock()

      il.Emit(OpCodes.Ret)


      Dim t As Type = tt.CreateType()

      ' Get a MethodInfo for TestMethod, and create a delegate to execute the
      ' method.
      Dim tmx As MethodInfo = t.GetMethod("TestMethod")
      Dim callTestMethod As StringSub = _
         CType([Delegate].CreateDelegate(GetType(StringSub), tmx), StringSub)

      ' Note that it is not necessary to declare your own delegate type. 
      ' Alternatively, you could use a generic delegate type as shown here:
      'Dim callTestMethod As Action(Of String) = _
      '   CType([Delegate].CreateDelegate(GetType(Action(Of String)), tmx), _
      '         Action(Of String))

      Example.PrintHelper("Normal execution, no exceptions thrown:")
      callTestMethod("test")


      Example.PrintHelper(vbLf & _
         "An exception is thrown and caught in the innermost block:")
      callTestMethod(Nothing)


      Example.PrintHelper(vbLf & _
         "An exception is thrown and not caught in the innermost block:")
      Try
         callTestMethod("")
      Catch ex As ArgumentException
         Example.PrintHelper("Demo: Caught ArgumentException """ & _
                             ex.Message & """")
      End Try
   End Sub 

   Delegate Sub StringSub(ByVal s As String)

   ' HELPER METHODS: The emitted code calls the ThrowHelper and PrintHelper 
   ' methods to throw exceptions conditionally and to display output. This 
   ' is done in order to simplify the emitted code.

   ' Throw ArgumentNullException if the argument is Nothing; if the argument
   ' has zero length, throw ArgumentException.
   Public Shared Sub ThrowHelper(ByVal text As String)
      If text Is Nothing Then
         Throw New ArgumentNullException("Parameter 'text' must not be null.")
      Else If text.Length = 0 Then
         Throw New ArgumentException("Parameter 'text' must have length > 0.")
      End If
   End Sub

   Private Shared outputBlock As System.Windows.Controls.TextBlock

   Public Shared Sub PrintHelper(ByVal msg As String)
      outputBlock.Text &= msg & vbLf
   End Sub

End Class 

' This example produces output similar to the following:
'
'Normal execution, no exceptions thrown:
'TestMethod: ThrowHelper ended normally.
'TestMethod: Finally block runs.
'
'An exception is thrown and caught in the innermost block:
'TestMethod: Caught ArgumentNullException.
'TestMethod: Finally block runs.
'
'An exception is thrown and not caught in the innermost block:
'TestMethod: Finally block runs.
'TestMethod: Fault block runs.
'Demo: Caught ArgumentException "Parameter 'text' must have length > 0."
using System;
using System.Reflection;
using System.Reflection.Emit;

public class Example
{
   public static void Demo(System.Windows.Controls.TextBlock outputBlock)
   {
      // Put the TextBlock in a location where the PrintHelper method can 
      // use it.
      Example.outputBlock = outputBlock;

      // Create the dynamic assembly. In Silverlight, dynamic assemblies are
      // transient and have only one module.
      AssemblyName aName = new AssemblyName("EmitDemo");
      AssemblyBuilder ab = 
         AppDomain.CurrentDomain.DefineDynamicAssembly(aName, 
                                                       AssemblyBuilderAccess.Run);
      ModuleBuilder mb = ab.DefineDynamicModule("EmitDemo");

      // Define a public type.
      TypeBuilder tt = mb.DefineType("TestType", TypeAttributes.Public);

      // Define the static TestMethod method, which has one string parameter and 
      // no return value. TestMethod passes its argument to Example.ThrowHelper,
      // which throws different exceptions depending on the value of the argument.
      // TestMethod handles one exception, and does not handle the other.
      MethodBuilder tm = 
         tt.DefineMethod("TestMethod", 
                         MethodAttributes.Public | MethodAttributes.Static, 
                         null, 
                         new Type[] { typeof(string) });

      // Get MethodInfo objects that represent the Example.PrintHelper method, 
      // for writing to the TextBlock, and Example.ThrowHelper, for throwing
      // exceptions conditionally.
      MethodInfo printhelper = typeof(Example).GetMethod("PrintHelper");
      MethodInfo throwhelper = typeof(Example).GetMethod("ThrowHelper");

      ILGenerator il = tm.GetILGenerator();

      // Begin the outermost exception block, which includes the fault handler.
      // The ECMA spec specifies that a protected block of code shall have only
      // one kind of handler.
      Label tryFault = il.BeginExceptionBlock();

      // Begin the middle exception block, which includes the finally handler.
      // There is no rule about the order of nesting of the fault and finally
      // handlers.
      Label tryFinally = il.BeginExceptionBlock();

      // Begin the innermost exception block, which includes the catch handlers.
      Label tryCatch = il.BeginExceptionBlock();

      // Load the argument string and pass it to the static Example.TestThrows
      // method. The called method throws different exceptions if the argument
      // is null or of zero length; it throws no exception otherwise.
      il.Emit(OpCodes.Ldarg_0);
      il.Emit(OpCodes.Call, throwhelper);

      // If the call to Example.TestThrows ended normally, display a message and
      // exit from the innermost exception block.
      il.Emit(OpCodes.Ldstr, "TestMethod: ThrowHelper ended normally.");
      il.Emit(OpCodes.Call, printhelper);
      il.Emit(OpCodes.Leave, tryCatch);

      // Catch ArgumentNullException, display a message, and exit from the inner
      // try/catch.
      il.BeginCatchBlock(typeof(ArgumentNullException));
      il.Emit(OpCodes.Ldstr, "TestMethod: Caught ArgumentNullException.");
      il.Emit(OpCodes.Call, printhelper);
      il.Emit(OpCodes.Leave, tryCatch);

      // The end of the innermost exception block. 
      il.EndExceptionBlock();


      // If the protected code ended normally, or if an exception was caught 
      // and handled, exit from the middle exception block.
      il.Emit(OpCodes.Leave, tryFinally);

      // The finally block displays a message.
      il.BeginFinallyBlock();
      il.Emit(OpCodes.Ldstr, "TestMethod: Finally block runs.");
      il.Emit(OpCodes.Call, printhelper);

      // The end of the middle exception block. 
      il.EndExceptionBlock();


      // If the protected code ended normally, or if an exception was caught 
      // and handled, exit from the outermost exception block.
      il.Emit(OpCodes.Leave, tryFault);


      // Begin the fault block, in the outermost exception block. The fault block
      // displays a message. As with finally blocks, you do not use a Leave to
      // exit from the fault block.
      il.BeginFaultBlock();
      il.Emit(OpCodes.Ldstr, "TestMethod: Fault block runs.");
      il.Emit(OpCodes.Call, printhelper);


      // The end of the outermost exception block.
      il.EndExceptionBlock();

      il.Emit(OpCodes.Ret);


      Type t = tt.CreateType();

      // Get a MethodInfo for TestMethod, and create a delegate to execute the
      // method.
      MethodInfo tmx = t.GetMethod("TestMethod");
      StringSub callTestMethod = 
         (StringSub) Delegate.CreateDelegate(typeof(StringSub), tmx);

      // Note that it is not necessary to declare your own delegate type. 
      // Alternatively, you could use a generic delegate type as shown here:
      //Action<String> callTestMethod = 
      //   (Action<String>) Delegate.CreateDelegate(typeof(Action<String>), tmx);

      Example.PrintHelper("Normal execution, no exceptions thrown:"  );
      callTestMethod("test");


      Example.PrintHelper(
         "\nAn exception is thrown and caught in the innermost block:");
      callTestMethod(null);


      Example.PrintHelper(
         "\nAn exception is thrown and not caught in the innermost block:");
      try
      {
         callTestMethod("");
      }
      catch(ArgumentException ex)
      {
         Example.PrintHelper(
            "Demo: Caught ArgumentException \"" + ex.Message + "\"");
      }
   }

   public delegate void StringSub(string s);

   // HELPER METHODS: The emitted code calls the ThrowHelper and PrintHelper 
   // methods to throw exceptions conditionally and to display output. This 
   // is done in order to simplify the emitted code.

   // Throw ArgumentNullException if the argument is Nothing; if the argument
   // has zero length, throw ArgumentException.
   public static void ThrowHelper(string text)
   {
      if (text == null)
      {
         throw new ArgumentNullException("Parameter 'text' must not be null.");
      }
      else if (text.Length == 0)
      {
         throw new ArgumentException("Parameter 'text' must have length > 0.");
      }
   }

   private static System.Windows.Controls.TextBlock outputBlock;

   public static void PrintHelper(string msg)
   {
      outputBlock.Text += msg + "\n";
   }
}

/* This example produces output similar to the following:

Normal execution, no exceptions thrown:
TestMethod: ThrowHelper ended normally.
TestMethod: Finally block runs.

An exception is thrown and caught in the innermost block:
TestMethod: Caught ArgumentNullException.
TestMethod: Finally block runs.

An exception is thrown and not caught in the innermost block:
TestMethod: Finally block runs.
TestMethod: Fault block runs.
Demo: Caught ArgumentException "Parameter 'text' must have length > 0."
 */

Version Information

Silverlight

Supported in: 5, 4, 3

Silverlight for Windows Phone

Supported in: Windows Phone OS 7.1

Platforms

For a list of the operating systems and browsers that are supported by Silverlight, see Supported Operating Systems and Browsers.