Tuesday, April 04, 2006 2:03 AM bart

CLR exception handling from A to Z - Everything you didn't want to know about try-catch-finally-fault-filter

What is it?

The principle of exceptions is a pretty easy-to-understand way to report exceptional situations to the consumer of a piece of code. Instead of using (artificial) HRESULT return values like this was the case in the (COM) past, exception handling is an object-oriented way to cope with exceptional situations. Basically, an exception object is an instance of some class (some == any class) which is thrown to when something exceptional goes wrong, for example a file I/O operation problem when a file is locked. The use of object types that inherit from System.Exception is actually not a direct requirement of the CLR (or the Virtual Execution System or VES). Essentially, exceptions are thrown when the current piece of code can't deal with the problematic situation and wants the caller to handle it further on. In order to handle such exceptions, a block of code must be protected which results in a so-called "protected block".

Throwing exceptions

We'll start by taking a look at throwing exceptions. If - on a certain point of the execution - you come to a point that you can't deal with yourself, you'll have to report this situation to the caller by throwing an exception. The first thing to do, is to decide which exception object to throw. You can use an existing exception (for example System.IO.IOException) or define an exception type yourself by inheriting from System.Exception (which is recommended when creating your own frameworks). Although the Common Language Infrastructure (CLI) allows any type of object to be used as an exception, the Common Language Specification (which aims to define a specification to allow for cross-language interoperability) dictates that every exception object is of type System.Exception (or a subtype). In order to define such a custom exception type, follow the next recommended rules:

  • Do not inherit directly from System.Exception but from System.ApplicationException;
  • Use Exception as the suffix of every exception class;
  • Provide at least the following three constructors:

    ...Exception() : base() {}
    ...Exception(string message) : base(message) {}
    ...Exception(string message, Exception innerException) : base(message, innerException) {}
     
  • Localize message strings and make sure the description message is correct from a linguistic point of view;
  • Chain exceptions using InnerException;
  • Prefer exceptions over error codes;
  • Do not throw exceptions as part of the normal control flow, only use it in exceptional situations (in a "normal program execution" no exceptions should occur);
  • Provide additional valuable information about the exception by defining extra properties wherever appropriate.

The throw statement takes the object on top of the stack and throws it as an exception. A typical piece of IL looks as follows:

newobj instance void MyException::.ctor()
throw

When an exception is thrown, a stack trace is created to trace back the origin of the exception.

Protected blocks

Catching exceptions is done by declaring a protected block (a.k.a. a try block or a guarded block) as we told before. Things brings us to the assiociated handlers:

  • a fault handler is called whenever an exception occurs but is not called as part of the normal control flow;
  • a type-filtered handler handles exceptions of a specified type (or subtype of the specified type) and is only called when such an exception was thrown, again it's not called as part of the normal control flow;
  • a user-filtered handler decides whether to handle an exception or not based on custom logic; if the test passes the handler will cope with the exception, otherwise the exception survives;
  • a finally handler is executed under any circumstance, regardless whether an exception occurs or not and can be used to close critical resources such as files or handles.

A protected region is a set of IL instructions marked as a try block which can have one or more handlers associated with it. Whenever an exception occurs within that try block, the CLR comes into play and takes over the execution flow to start executing the handler that was selected to deal with the exception (if any). If no handler was found, the exception is propagated up the call stack. Also notice I said "whenever an exception occurs", which does not necessarily mean that an exception was thrown by the called code. Rather, the runtime can also throw an exception under exceptional circumstances. Examples include a DivideByZeroException, a StackOverflowException, an OutOfMemoryException, a NullReferenceException, a MissingMethodException, etc.

Try and catch

Let's take a look at the underlying IL support to define protected blocks:

.try
{
   // code block
}

There's also an alternative which will be covered further on, but first we'll take a closer look at handler blocks. Basically, a handler block is nothing more than a block of IL code but used in the context of exception handling. One such a block is of course the well-known catch block which performs type-filtered exception handling:

.try
{
   // code block
}
catch MyException
{
   // exception handler code block
}

Actually this looks pretty much like C#, just because the sample is stripped down quite a bit. For example, we omitted the code to leave the try block and catch block when the blocks reach their end. This is required and looks as follows:

.try
{
   // code block
   leave afterTryCatchBlock
}
catch MyException
{
   // exception handler code block
   leave afterTryCatchBlock
}
afterTryCatchBlock: ...

Let's try to create a first example purely by using IL code. Open a Visual Studio 2005 Command Prompt, open Notepad and create a file called demo1.il. Copy the following into it:

.assembly Demo1
{
}

.class Demo1 extends [mscorlib]System.Object
{
   .method public static void Main()
   {
      .entrypoint
      .try
      {
         call void Demo1::Do2()
         leave.s exitTryCatchBlock
      }
      catch MyException
      {
         leave.s exitTryCatchBlock
      }
      exitTryCatchBlock: ret
   }

   .method private static void Do2()
   {
      newobj instance void MyException::.ctor()
      throw
   }

   .method public instance void .ctor()
   {
      ldarg.0
      call instance void [mscorlib]System.Object::.ctor()
      ret
   }
}

.class MyException extends [mscorlib]System.ApplicationException
{
   .method public instance void .ctor()
   {
      ldarg.0
      call instance void [mscorlib]System.Exception::.ctor()
      ret
   }
}

Next, assemble the IL code using ilasm.exe by calling ilasm.exe demo1.il. This will create an executable demo1.exe which can be executed. Let's make it a bit more fancy and put something on the screen about the exception (demo2.il):

.assembly Demo2
{
}

.class Demo2 extends [mscorlib]System.Object
{
   .method public static void Main()
   {
      .entrypoint
      .try
      {
         call void Demo2::Do2()
         leave.s exitTryCatchBlock
      }
      catch MyException
      {
         call instance string [mscorlib]System.Exception::get_Message()
         call void [mscorlib]System.Console::WriteLine(string)
         leave.s exitTryCatchBlock
      }
      exitTryCatchBlock: ret
   }

   .method private static void Do2()
   {
      ldstr "Test"
      newobj instance void MyException::.ctor(string)
      throw
   }

   .method public instance void .ctor()
   {
      ldarg.0
      call instance void [mscorlib]System.Object::.ctor()
      ret
   }
}

.class MyException extends [mscorlib]System.ApplicationException
{
   .method public instance void .ctor(string)
   {
      ldarg.0
      ldarg.1
      call instance void [mscorlib]System.Exception::.ctor(string)
      ret
   }
}

I mentioned there's also an alternative to declare a protected block and to cope with a handler. Instead of using the curly brace syntax, you can also put the whole .try ... catch "statement" on one single line referring to the various blocks, as follows (demo3.il):

.assembly Demo3
{
}

.class Demo3 extends [mscorlib]System.Object
{
   .method public static void Main()
   {
      .entrypoint
      IL_0001: call void Demo3::Do3()
      IL_0002: leave.s IL_0006
      IL_0003: call instance string [mscorlib]System.Exception::get_Message()
      IL_0004: call void [mscorlib]System.Console::WriteLine(string)
      IL_0005: leave.s IL_0006
      IL_0006: ret
      .try IL_0001 to IL_0002 catch MyException handler IL_0003 to IL_0005
   }

   .method private static void Do3()
   {
      ldstr "Test"
      newobj instance void MyException::.ctor(string)
      throw
   }

   .method public instance void .ctor()
   {
      ldarg.0
      call instance void [mscorlib]System.Object::.ctor()
      ret
   }
}

.class MyException extends [mscorlib]System.ApplicationException
{
   .method public instance void .ctor(string)
   {
      ldarg.0
      ldarg.1
      call instance void [mscorlib]System.Exception::.ctor(string)
      ret
   }
}

Defining multiple catch blocks is of course not a problem too. Assume a piece of code can throw a MyFirstException and a MySecondException exception both deriving from System.ApplicationException directly, then you could write the following guard:

.try
{
   // do something
   leave.s exitTryCatchBlock
}
catch MyFirstException
{
   // catch it somehow
   leave.s exitTryCatchBlock
}
catch MySecondException
{
   // catch it somehow
   leave.s exitTryCatchBlock
}
exitTryCatchBlock: // continue after the block

Of course the alternative one-line syntax can be used too. For multiple catch blocks and using more friendly-named labels, this looks pretty cute:

.try BeginTry1 to EndTry1
  catch MyException
    handler BeginMyExceptionHandler to EndMyExceptionHandler
  catch MySecondException
    handler BeginMySecondExceptionHandler to EndMySecondExceptionHandler

<Warning>

Take a look at the following piece of code:

.try
{
   // do something which throws MyException
   leave.s exitTryCatchBlock
}
catch [mscorlib]System.Exception
{
   ldstr "First"
   call void [mscorlib]System.Console::WriteLine(string)
   leave.s exitTryCatchBlock
}
catch MyException
{
   ldstr "Second"
   call void [mscorlib]System.Console::WriteLine(string)
   leave.s exitTryCatchBlock
}
exitTryCatchBlock: // continue after the block

This piece of code will always print "First" on the screen because the System.Exception catch block is investigated prior to investigating the MyException catch block. Essentially, once you have a block catch A { .. } all further catch blocks that specify a type that derives from A are unreachable. In contrast, the following piece of code will print "Second":

.try
{
   // do something which throws MyException
   leave.s exitTryCatchBlock
}
catch MyException
{
   ldstr "Second"
   call void [mscorlib]System.Console::WriteLine(string)
   leave.s exitTryCatchBlock
}
catch [mscorlib]System.Exception
{
   ldstr "First"
   call void [mscorlib]System.Console::WriteLine(string)
   leave.s exitTryCatchBlock
}
exitTryCatchBlock: // continue after the block

Notice that the Visual Basic compiler and the C# compiler will generate a warning and an error respectively if a catch block is unreachable (different behavior depending on the language compiler):

warning BC42029: 'Catch' block never reached, because 'MyException' inherits from 'System.Exception'.
error CS0160: A previous catch clause already catches all exceptions of this or of a super type ('System.Exception')

</Warning>

Catch it all

Sometimes you just want to catch every possible exception that occurs in a guarded block (for example in the entrypoint of the application to terminate the application in a friendly fashion in case of an unforeseen non anticipated exception). This is done using a catch-all block which is in fact just a higher-level language construct. An example in C# is the following:

try
{
   // do something
}
catch
{
   // catch all exceptions
}

In Visual Basic this looks like:

Try
   ' do something
Catch
   ' catch all exceptions
End Try

As the matter in fact, both pieces of code produce different IL. This is the C# way of working:

.try
{
   IL_0002: call void Ex::Do()
   IL_0009: leave.s IL_0016
} // end .try
catch [mscorlib]System.Object
{
   IL_000b: pop
   IL_000d: call void Ex::Clean()
   IL_0014: leave.s IL_0016
} // end handler

In Visual Basic you'll get something slightly different:

.try
{
   IL_0000: call void Ex::Do()
   IL_0005: leave.s IL_0018
} // end .try
catch [mscorlib]System.Exception
{
   IL_0007: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::SetProjectError(class [mscorlib]System.Exception)
   IL_000c: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::ClearProjectError()
   IL_0011: call void Ex::Clean()
   IL_0016: leave.s IL_0018
} // end handler

<Remark>
Wondering what the SetProjectError and ClearProjectError stuff is used for in Visual Basic? The answer is to support backward compatibility with On Error syntax.
</Remark>

The piece of code we're looking at right now is the piece which contains the catch clause. As you can see, C# follows the CLI convention by using System.Object as the root for exceptions whileas Visual Basic follows the CLS. However, this does not mean you can do something like

throw new MyClassNotDerivingFromException();

in C# which would result in the following compiler error:

error CS0155: The type caught or thrown must be derived from System.Exception

In most cases however, you'll code a catch-all using System.Exception in the "catch clause signature", at least when you want to do something with the exception object such as getting the Message property value:

try
{
   // do something
}
catch (Exception ex)
{
   // catch all exceptions
}

In Visual Basic this looks like:

Try
   ' do something
Catch ex As Exception
   ' catch all exceptions
End Try

Notice C# also allows you to write this:

try
{
   // do something
}
catch (Exception)
{
   // catch all exceptions
}

Finally handlers

As mentioned before, a finally handler is called under any circumstance no matter whether an exception has occurred or not. In a higher-level language this might look as follows:

try
{
   Do();
}
catch (MyException ex)
{
   Console.WriteLine("Catch");
}
finally
{
   Console.WriteLine("Finally");
}

First of all, you can omit the catch block if you don't need it. In such a case, the IL code is rather predictable (you can infer it from the following piece of code). However the sample above has a combined catch and finally block, which gets translated into two nested .try blocks:

 .try
{
   .try
   {
      call void Demo5::Do()
      leave.s exitSecondTry
   }
   catch MyException
   {
      ldstr "Catch"
      call void [mscorlib]System.Console::WriteLine(string)
      leave.s exitFirstTry
   }
   exitFirstTry: leave.s exitSecondTry
}
finally
{
   ldstr "Finally"
   call void [mscorlib]System.Console::WriteLine(string)
   endfinally
}
exitSecondTry: ret

Executing this piece of code will always print "Finally" on the screen. Whether "Catch" is printed on the screen depends on the guarded block's behavior (i.e. whether the call to Do() throws a MyException). Notice the mandatory endfinally instruction at the bottom of the finally block. I guess you're mature enough now to find out how to ilasm this piece of code inside a valid .il file. Again a shorthand syntax can be used looking like this:

.try IL_abc to IL_def finally handler IL_ghi to IL_jkl

Another place where the finally clause is used (implicitly) is the IDisposable pattern in combination with the using block syntax in C# and (since .NET 2.0) also in Visual Basic. Assume the following piece of C# code:

using (new Ex())
{
   //do something
}

on a class defined as

class Ex : IDisposable
{
   public void Dispose() {}
}

which translates into the following piece of IL (cut needless pieces):

IL_0001: newobj instance void Ex::.ctor()
IL_0006: stloc.1
.try
{
   IL_0009: leave.s IL_001b
} // end .try
finally
{
   IL_000b: ldloc.1
   IL_000c: ldnull
   IL_000d: ceq
   IL_000f: stloc.2
   IL_0010: ldloc.2
   IL_0011: brtrue.s IL_001a
   IL_0013: ldloc.1
   IL_0014: callvirt instance void [mscorlib]System.IDisposable::Dispose()
   IL_001a: endfinally
} // end handler
IL_001b: nop

Basically the code matches to the following:

Ex ex = new Ex();
try
{
   //do something
}
finally
{
   if (ex != null)
      ex.Dispose();
}

Fault handlers

You just saw that finally handlers are called regardless of the result of the guarded block. A fault handler is slightly different in a sense that the fault block is only called when an exception has occurred after which the exception keeps propagating up the stack (unless the whole thing is embedded in yet another guard block that catches the exception of course). An example will make things more clear:

.method public static void Main()
{
   .entrypoint
   .try
   {
      call void Demo6::Do2()
      leave.s exitTry
   }
   fault
   {
      ldstr "Fault"
      call void [mscorlib]System.Console::WriteLine(string)
      endfault
   }
   exitTry: ret
}

Again Do2() is the bad guy throwing a MyException exception. The application will crash but "Fault" will be printed on the screen. Actually the fault handler has had the chance to do some work but leaving the exception alone. However, this feature is (as far as I know) not exposed through the well-known .NET languages such as C# and Visual Basic (well, honestely, I know about a case in which the C++ compiler takes advantage of a fault-block to "fake" deterministic finalization when you have declared a finalizer using the !ClassName() syntax). You can get a similar behavior by combining a catch and (re)throw. As a little side-note I want to mention that endfault is just an alias for endfinally and both translate to the same opcode.

User-filtered handlers

The last type of handler supported by the CLR is the so-called user-filtered handler, or shortly "filters". In my opinion filters are a great piece of technology but unfortunately it's only available to Visual Basic developers (thus not for C# developers) which is a pitty because C# would - again in my opinion - benefit from this, altough it's possible (as I'll show below) to accomplish the same in C# with some other piece of code (although there is some difference in performance). But let's get start by taking a look at a little example in Visual Basic that uses filters:

Imports System

Module When1 'When is a keyword, so we need to use When1 for our method name because the lack of context-sensitivity in the compiler
   Public Sub Main()
      TestWithFilter()
      TestWithoutFilter()
   End Sub

   Public Sub TestWithFilter()
      Try
         Do2
      Catch ex As MyException When ex.Code = 1
        
'Catch it
      End Try
   End Sub

   Public Sub TestWithoutFilter()
      Try
         Do2
      Catch ex As MyException
         If ex.Code = 1 Then
            'Catch it
         Else
            Throw
         End If
      End Try
   End Sub

   Private Sub Do2 'Do is a keyword, so we need to use Do2 for our method name because the lack of context-sensitivity in the compiler
      Throw New MyException(1)
   End Sub
End Module

Class MyException
Inherits Exception
   Public Code As Integer
   Public Sub New(code as Integer)
      MyBase.New()
      Me.Code = code
   End Sub
End Class

Both the TestWithFilter and TestWithoutFilter have the same behavior. However, the first one uses user-defined filters whileas the other one uses procedural code to determine whether the exception should be caught and rethrows the exception (Check out my blog post about "To throw or to rethrow?" too for more advanced information on rethrowing exception.) if that's not the case. So, how does this piece of magic filtering look like in terms of IL-code? A quick peek:

.method public static void TestWithFilter() cil managed
{
   // Code size 49 (0x31)
   .maxstack 3
   .locals init (class MyException V_0)
   IL_0000: call void When1::Do2()
   IL_0005: leave.s IL_0030
   IL_0007: isinst MyException
   IL_000c: dup
   IL_000d: brtrue.s IL_0013
   IL_000f: pop
   IL_0010: ldc.i4.0
   IL_0011: br.s IL_0026
   IL_0013: dup
   IL_0014: stloc.0
   IL_0015: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::SetProjectError(class [mscorlib]System.Exception)
   IL_001a: ldloc.0
   IL_001b: ldfld int32 MyException::Code
   IL_0020: ldc.i4.1
   IL_0021: ceq
   IL_0023: ldc.i4.0
   IL_0024: cgt.un
   IL_0026: endfilter

   IL_0028: pop
   IL_0029: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::ClearProjectError()
   IL_002e: leave.s IL_0030
   IL_0030: ret
   .try IL_0000 to IL_0007 filter IL_0007 handler IL_0028 to IL_0030
} // end of method When1::TestWithFilter

The last line is the most important one, containing the (short-hand syntax'd) try block declaration, including the filter. Here is how it works:

  1. Line IL_0000 to IL_0007 are executed under the vigilant try block looking for exceptions to occur. Actually, in ... to ... regions you have to exclude the last referred line, so in reality lines IL_0000 to IL_0005 are guarded.
  2. The .try block has one handler associated, being a user-defined filter defined on line IL_0007 and running till the endfilter statement is encountered. The filter leaves a value on the stack indicating whether the filter test passes (EXCEPTION_EXECUTE_HANDLER) or not. Basically, a 1 value is used to indicate the filter passes whileas 0 indicates a failure (EXCEPTION_CONTINUE_SEARCH). Actually this approach is borrowed from SEH in Windows (see Platform SDK for more information, look for Structured Exception Handling).
  3. And last but not least, the associated handler logic can be found in lines IL_0028 to IL_002e (again, exclude the last referred line).

Doing the same in C# requires you to take the TestWithoutFilter-like approach:

   void TestWithoutFilter()
   {
      try
      {
         Do2();
      }
      catch (MyException ex)
      {
         if (ex.Code == 1)
            // Catch it
         else
            throw;
      }
   }

This approach has one drawback however: performance. Let's take a look at a complete (self-written) lightweight IL-sample of filtering:

.assembly Demo7
{
}

.class public Demo7 extends [mscorlib]System.Object
{
   .method public static void WithFilter()
   {
      IL_0000: call void Demo7::Do2()
      IL_0001: leave.s IL_0020
      IL_0002: dup                           // _ ex ex
      IL_0003: isinst MyException            // _ ex (ex is MyException)
      IL_0004: brtrue.s IL_0008              // _ ex
      IL_0005: pop                           // _
      IL_0006: ldc.i4.0                      // _ 0
      IL_0007: br.s IL_000b                  // _ 0
      IL_0008: ldfld int32 MyException::Code // _ ex.Code
      IL_0009: ldc.i4.1                      // _ ex.Code 1
      IL_000a: ceq                           // _ (ex.Code == 1)
      IL_000b: endfilter
      IL_0010: nop //ldstr "You have been caught"
      IL_0011: nop //call void [mscorlib]System.Console::WriteLine(string)
      IL_0012: leave.s IL_0020
      IL_0020: ret
      .try IL_0000 to IL_0002 filter IL_0002 handler IL_0010 to IL_0020
   }

   .method public static void WithoutFilter()
   {
      IL_0000: call void Demo7::Do2()
      IL_0001: leave.s IL_0020
      IL_0002: ldfld int32 MyException::Code // _ ex.Code
      IL_0003: ldc.i4.1                      // _ ex.Code 1
      IL_0004: ceq                           // _ (ex.Code == 1)
      IL_0005: brtrue.s IL_0010              // _
      IL_0006: rethrow
      IL_0010: nop //ldstr "You have been caught"
      IL_0011: nop //call void [mscorlib]System.Console::WriteLine(string)

      IL_0012: leave.s IL_0020
      IL_0020: ret
      .try IL_0000 to IL_0002 catch MyException handler IL_0002 to IL_0020
   }

   .method private static void Do2()
   {
      ldc.i4.1
      newobj instance void MyException::.ctor(int32)
      throw
   }

   .method public instance void .ctor()
   {
      ldarg.0
      call instance void [mscorlib]System.Object::.ctor()
      ret
   }
}

.class MyException extends [mscorlib]System.ApplicationException
{
   .field public int32 Code

   .method public instance void .ctor(int32)
   {
      ldarg.0
      call instance void [mscorlib]System.Exception::.ctor()
      ldarg.0
      ldarg.1
      stfld int32 MyException::Code
      ret
   }
}

This piece of sample code shows a basic filter without the Visual Basic plumbing (see WithFilter) as well as the equivalent with a catch-rethrow approach (see WithoutFilter). The fuchsia-colored piece of comment code is actually the stack transition graph which I'm adding for self-support while writing raw IL-code. Assemble the demo file using ilasm.exe /DLL demo7.il which generates a demo7.dll file. Notice that - for performance testing - I've disabled statements IL_0010 and IL_0011 by means of a nop statement. It's also important to mark the Demo7 class as public in order to be able to use it further on.

Because it's still possible to write code with C#, let's actually use our generated assembly from within C# to call the functionality and to perform some performance measurement. Create a file called Demo7Test.cs and add the following code:

using System;
using System.Diagnostics;

class Demo7Test
{
   public static void Main()
   {
      Stopwatch watch = new Stopwatch();
      watch.Start();
      for (int i = 0; i < 10000; i++)
         Demo7.WithoutFilter();
      watch.Stop();
      Console.WriteLine("Unfiltered: {0}", watch.Elapsed);

      watch.Start();
      for (int i = 0; i < 10000; i++)
         Demo7.WithFilter();
      watch.Stop();
      Console.WriteLine("Filtered: {0}", watch.Elapsed);
   }
}

Compile this piece of code using csc.exe /r:Demo7.dll Demo7Test.cs which will produce a .exe file consuming our .dll file (which we have written completely in IL). The result on my machine looks as follows:

Unfiltered: 00:00:00.3097402
Filtered: 00:00:00.5927644

From this, we could conclude filtering is slower than unfiltered exception handling with custom logic to find out whether the caught exception can be handled successfully based on certain criteria. However, we didn't test the rethrow path in this sample so everything will depend on the distribution of passes and failures in the filtering logic. Notice that although the When-clause of Visual Basic is part of the Catch syntax line, it doesn't get translated to a catch handler at all. Instead Catch ex As MyException When ex.Code = 1 gets translated to a filter that performs type-checking as its first check (isinst MyException). If I find some extra time ever, I'll continue to trace the bottleneck in the filtered piece of code in order to report more thorough investigations.

Conclusion

Exception management in .NET is far more complex than you might think at first glance. Also, not all .NET languages expose all of the exception management richness of the CLR platform underneath. One notable example is the lack of filters in C# whileas the VB guys have included this kind of support on the product (to boost developer's productivity should be the official explanation).

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Filed under: ,

Comments

# Visual Basic 2005 On Tour

Tuesday, April 04, 2006 2:12 AM by B# .NET Blog

Yesterday, I've been to the Visual Basic 2005 On Tour event in Brussels. About 200 attendees were there...

# re: CLR exception handling from A to Z - Everything you didn't want to know about try-catch-finally-fault-filter

Tuesday, April 04, 2006 5:04 PM by Jens

I did not try it, but IIRC you can put [] around identifiers when they equal a keyword.

So you could write :

Module [When]
...

Private Sub [Do]
...
End Sub
End Module

# re: CLR exception handling from A to Z - Everything you didn't want to know about try-catch-finally-fault-filter

Monday, April 10, 2006 9:10 AM by Kristof Verbiest

Personally, I would add a rule to define a custom exception type: make the type [Serializable]. Otherwise the exception will not be marshalled when doing cross-AppDomain calls using .NET remoting.

# Generics and covariance/contravariance

Tuesday, October 09, 2007 9:17 AM by Adventures in .net and other Microsoft worlds

Today I was writing code that looks like this: public interface IChild {} public class GenericSet where TChild : IChild {} public class SpecificSet : GenericSet

# RAII vs. exceptions | Ask &amp; Answers

Monday, October 28, 2013 11:09 PM by RAII vs. exceptions | Ask & Answers

Pingback from  RAII vs. exceptions | Ask &amp; Answers

# RAII vs. exceptions | Technology &amp; Programming Answers

Monday, November 04, 2013 11:20 PM by RAII vs. exceptions | Technology & Programming Answers

Pingback from  RAII vs. exceptions | Technology &amp; Programming Answers