BeginExceptionBlock Method

ILGenerator.BeginExceptionBlock Method

[ This article is for Windows Phone 8 developers. If you’re developing for Windows 10, see the latest documentation. ]

Begins an exception block for a non-filtered exception.

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

public virtual Label BeginExceptionBlock()

Return Value

Type: System.Reflection.Emit.Label
The label for the end of the block. This will leave you in the correct place to execute finally blocks or to finish the try.

Creating an exception block records some information, but does not actually emit any Microsoft intermediate language (MSIL) onto the stream.

The following example demonstrates the use of exception blocks. The example defines a method with a try/catch exception block nested in a try/finally exception block. (This is the equivalent of a try/catch/finally statement in C# or Visual Basic. In MSIL, an exception block can have only one kind of handler, so the try/catch block must be nested in the try/finally block.) In the try/catch block, the example throws an exception, catches it, and displays a message. In the finally block, the example displays a text message.


using System;
using System.Reflection;
using System.Reflection.Emit;

class Example
{
   public static void Demo(System.Windows.Controls.TextBlock outputBlock)
   {
      AssemblyName myAsmName = new AssemblyName("AdderExceptionAsm");
      AssemblyBuilder myAsmBldr = 
         AppDomain.CurrentDomain.DefineDynamicAssembly(myAsmName, 
                                                       AssemblyBuilderAccess.Run);
      ModuleBuilder myModBldr = myAsmBldr.DefineDynamicModule(myAsmName.Name);


      TypeBuilder myTypeBldr = myModBldr.DefineType("Adder", TypeAttributes.Public);


      // Demo output section ------------------------------
      // Define a static field that holds the TextBlock control, so the static
      // methods of Adder can display messages while the demo is running. 
      //
      Type obType = outputBlock.GetType();
      FieldBuilder demoOutput = 
         myTypeBldr.DefineField("OutputBlock", 
                                obType, 
                                FieldAttributes.Public | FieldAttributes.Static);

      // To obtain the current text from the TextBlock control, and to store
      // the updated value, obtain the "get" and "set" accessors for the Text
      // property:
      PropertyInfo textProp = obType.GetProperty("Text");
      MethodInfo getter = textProp.GetGetMethod();
      MethodInfo setter = textProp.GetSetMethod();

      // To concatenate two strings, get the static Concat(String, String) method 
      // of the String class:
      MethodInfo concat2 = 
         typeof(string).GetMethod("Concat", 
                                  BindingFlags.Public | BindingFlags.Static, 
                                  Type.DefaultBinder, 
                                  new Type[]{ typeof(string), typeof(string) }, null);
      // ------------------------------ Demo output section


      Type[] adderParams = { typeof(int), typeof(int) };

      // The DoAdd method adds two numbers which are 100 or less. If either of the
      // input values is greater than 100, the method throws an exception, catches
      // it, and displays a message on the TextBlock stored in the static field
      // named OutputBlock. The method also displays a message from its finally
      // block. The method returns an integer. 
      MethodBuilder adderBldr = 
         myTypeBldr.DefineMethod("DoAdd", 
                                 MethodAttributes.Public | MethodAttributes.Static, 
                                 typeof(int), 
                                 adderParams);

      ILGenerator adderIL = adderBldr.GetILGenerator();

      // The exception that is thrown by DoAdd.
      Type overflowType = typeof(OverflowException);


      // Declare local variables to hold the result of the addition, and the
      // exception that is caught by the Catch block.
      LocalBuilder result = adderIL.DeclareLocal(typeof(int));
      LocalBuilder thrownException = adderIL.DeclareLocal(overflowType);


      // Define labels for branching. The labels can be used immediately in Emit
      // calls, but they do not acquire their target locations until the 
      // MarkLabel(Label) method is called at the location in the program that
      // the label applies to.
      //
      Label succeeded = adderIL.DefineLabel();
      Label skipOutputInFinally = adderIL.DefineLabel();
      Label skipOutputInCatch = adderIL.DefineLabel();


      // Begin the try/catch/finally block. The label is used to leave the
      // block.
      Label exTryCatchFinally = adderIL.BeginExceptionBlock();

      // Load the first argument and the integer value 100 onto the execution
      // stack, and test whether the argument is greater than 100. The result is
      // now on the execution stack.
      //
      adderIL.Emit(OpCodes.Ldarg_0);
      adderIL.Emit(OpCodes.Ldc_I4_S, 100);
      adderIL.Emit(OpCodes.Cgt);

      // Test whether the second argument is greater than 100. Both results are
      // now on the execution stack.
      //
      adderIL.Emit(OpCodes.Ldarg_1);
      adderIL.Emit(OpCodes.Ldc_I4_S, 100);
      adderIL.Emit(OpCodes.Cgt);

      // Perform a logical OR on the two results, and branch to the 'succeeded'
      // label if the result is true.
      adderIL.Emit(OpCodes.Or);
      adderIL.Emit(OpCodes.Brfalse, succeeded);


      // If one of the arguments was greater than 100, throw an OverflowException. 
      adderIL.ThrowException(overflowType);

      // This example uses the ThrowException method, which uses the default 
      // constructor of the specified exception type to create the exception. If you
      // want to specify your own message, you must use a different constructor; 
      // replace the ThrowException method call with code like that shown below,
      // which creates the exception and throws it.
      //
      // Load the message, which is the argument for the constructor, onto the 
      // execution stack. Execute Newobj, with the OverflowException constructor
      // that takes a string. This pops the message off the stack, and pushes the
      // new exception onto the stack. The Throw instruction pops the exception off
      // the stack and throws it.
      //adderIL.Emit(OpCodes.Ldstr, "DoAdd does not accept values over 100.");
      //adderIL.Emit(OpCodes.Newobj, _
      //             overflowType.GetConstructor(new Type[] { typeof(String) }));
      //adderIL.Emit(OpCodes.Throw);


      // If both arguments are less than or equal to 100, execution continues 
      // here.
      adderIL.MarkLabel(succeeded);

      // Load the arguments onto the stack, add them, and store the result in the
      // local variable named result.
      adderIL.Emit(OpCodes.Ldarg_0);
      adderIL.Emit(OpCodes.Ldarg_1);
      adderIL.Emit(OpCodes.Add_Ovf_Un);
      adderIL.Emit(OpCodes.Stloc_S, result);

      // Use the Leave instruction to exit a try block. You cannot branch from try
      // blocks.
      adderIL.Emit(OpCodes.Leave, exTryCatchFinally);


      // Start the catch block for OverflowException.
      //
      adderIL.BeginCatchBlock(overflowType);

      // On entry to the catch block, the thrown exception is on the stack. Store it
      // in a local variable.
      adderIL.Emit(OpCodes.Stloc_S, thrownException);


      // Load the Shared field that contains the TextBlock. Load Nothing, and compare
      // the two for equality. If they are equal, skip over the output section.
      adderIL.Emit(OpCodes.Ldsfld, demoOutput);
      adderIL.Emit(OpCodes.Ldnull);
      adderIL.Emit(OpCodes.Ceq);
      adderIL.Emit(OpCodes.Brtrue_S, skipOutputInCatch);


      // The exception text is appended to the Text property of the TextBlock. That
      // means the get accessor method (getter) is called to fetch the existing 
      // value, then the message is constructed and concatenated, and finally the
      // set accessor method (setter) is called to set the new value. The TextBlock
      // object is needed twice, once for the getter and once for the setter, so 
      // load it twice and then call the getter. Calling the getter pops the second
      // TextBlock reference off the stack, and pushes the value of the Text property
      // onto the stack.
      adderIL.Emit(OpCodes.Ldsfld, demoOutput);
      adderIL.Emit(OpCodes.Ldsfld, demoOutput);
      adderIL.Emit(OpCodes.Callvirt, getter);

      // Format the exception text: Load a format string, then load the exception
      // from the local variable. Call the overload of the Shared String.Format 
      // method that takes a format string and an object. If the object is not
      // already a string, the Format function calls its ToString() method.
      //
      adderIL.Emit(OpCodes.Ldstr, "Caught: {0}\n");
      adderIL.Emit(OpCodes.Ldloc_S, thrownException);
      adderIL.Emit(OpCodes.Call, 
                   typeof(string).GetMethod("Format", 
                                            new Type[] { typeof(string), typeof(object) }));

      // The execution stack now has a reference to the TextBlock, the old value
      // of its Text property, and the formatted string. Use the String.Concat
      // method to concatenate the old value of the Text with the formatted string.
      // Now the stack contains the TextBlock and the new value. Call the setter 
      // for the Text property, which pops the TextBlock and the value off the 
      // stack and sets the property.
      //
      adderIL.Emit(OpCodes.Call, concat2);
      adderIL.Emit(OpCodes.Callvirt, setter);


      // Assign this location to the label that skips the output.
      adderIL.MarkLabel(skipOutputInCatch);

      // The addition failed, but the function has to return an integer value, so
      // store -1 in the local variable named result. Use the Leave instruction to
      // exit the catch block. The finally block will be executed.
      //
      adderIL.Emit(OpCodes.Ldc_I4_M1);
      adderIL.Emit(OpCodes.Stloc, result);
      adderIL.Emit(OpCodes.Leave_S, exTryCatchFinally);


      adderIL.BeginFinallyBlock();

      // The finally block block displays a message on the TextBlock, if the 
      // OutputBlock field has been set. Just as in the catch block, the following
      // code tests whether the TextBlock is present, and skips the output if it is
      // not present.
      adderIL.Emit(OpCodes.Ldsfld, demoOutput);
      adderIL.Emit(OpCodes.Ldnull);
      adderIL.Emit(OpCodes.Ceq);
      adderIL.Emit(OpCodes.Brtrue_S, skipOutputInFinally);

      // Append a constant string to the Text property of the TextBlock.
      adderIL.Emit(OpCodes.Ldsfld, demoOutput);
      adderIL.Emit(OpCodes.Ldsfld, demoOutput);
      adderIL.Emit(OpCodes.Callvirt, getter);
      adderIL.Emit(OpCodes.Ldstr, "Executing the finally block.\n");
      adderIL.Emit(OpCodes.Call, concat2);
      adderIL.Emit(OpCodes.Callvirt, setter);

      adderIL.MarkLabel(skipOutputInFinally);
      // This is the end of the try/catch/finally block.
      adderIL.EndExceptionBlock();


      // The end of the method. If no exception was thrown, the correct value
      // is saved in result. If an exception was thrown, result will be equal
      // to -1. Load the value of result onto the stack and return.
      //
      adderIL.Emit(OpCodes.Ldloc, result);
      adderIL.Emit(OpCodes.Ret);

      // Complete the type.
      Type adderType = myTypeBldr.CreateType();


      // Assign the TextBlock to the Shared OutputBlock field of Adder.
      adderType.InvokeMember("OutputBlock", BindingFlags.SetField, null, null, 
                             new object[] { outputBlock });

      // Create an array of input arguments.
      object[] addParams = { 42, 43 };


      // Invoke Adder.DoAdd and save the result. The finally block appends its 
      // message to the Text property. 
      // IMPORTANT: Do not format the result and concatenate it to the Text property
      // in this statement. Like the concatenation operations in the emitted code, 
      // the old Text property value would be pushed onto the execution stack at the 
      // beginning of the statement; the messages that the DoAdd method appends to 
      // the Text property during its execution would not be part of that value, and
      // therefore would be lost.
      object sum = adderType.InvokeMember("DoAdd", BindingFlags.InvokeMethod, null, null, 
                                          addParams);

      outputBlock.Text += String.Format("{0} + {1} = {2}\n", 
                                        addParams[0], addParams[1], sum);

      // Change the second argument to a number greater than 100, and invoke DoAdd
      // again. The exception is thrown and caught, and displayed in the TextBlock.
      // The finally block appends its message.
      addParams[1] = 143;
      sum = adderType.InvokeMember("DoAdd", BindingFlags.InvokeMethod, null, null, 
                                   addParams);
      outputBlock.Text += String.Format("{0} + {1} = {2}\n", 
                                        addParams[0], addParams[1], sum);


      // Set the Shared OutputBlock field to Nothing, and invoke DoAdd again. This 
      // time DoAdd displays no messages. 
      adderType.InvokeMember("OutputBlock", BindingFlags.SetField, null, null, 
                             new object[] { null });
      sum = adderType.InvokeMember("DoAdd", BindingFlags.InvokeMethod, null, null, 
                                   addParams);
      outputBlock.Text += String.Format("{0} + {1} = {2}\n", 
                                        addParams[0], addParams[1], sum);
   }
}

/* This code example produces output similar to the following:

Executing the finally block.
42 + 43 = 85
Caught: System.OverflowException: Arithmetic operation resulted in an overflow.
   at Adder.DoAdd(Int32 , Int32 )
Executing the finally block.
42 + 143 = -1
42 + 143 = -1
 */


Windows Phone OS

Supported in: 8.1, 8.0, 7.1

Windows Phone

Show:
© 2017 Microsoft