Click here to Skip to main content
Click here to Skip to main content

Simplifying Exception-Safe Code

By , 1 Apr 2003
 

Introduction

Writing correct code in the presence of exceptions is no easy task. Exceptions introduce a control flow that is very different from normal program flow. And it takes some forethought and careful coding to guarantee the consistency and predictability of a program in the (not so) unlikely event of throwing exceptions.

It is no wonder then that most developers write their code with the total disregard to exception safety. We always assume that we can "fix it" later on, which most often ends up to be in a bug report from a very unhappy customer using the released product.

But What is Exception Safety?

In his remarkable book--Exceptional C++--Herb Sutter defines the various levels of exception safety. While his treatment is focused on C++, I find his definitions applicable to C#, and indeed to any language that supports the notion of exceptions. According to his definition, there are three levels of exception safety:

  • Strong Guarantee, in which case an operation failing because of an exception will not alter the program state. This implies that such operation is treated as an atomic unit, which implies some form of commit-or-rollback semantics. That basically means that client code calling a function will perceive no side effects if that function throws an exception.
  • Basic Guarantee, which only guarantees that throwing an exception will not leak any resources, but side effects may arise still. The effect of leaking resources isn't a big issue due to garbage collection of managed resources. But it can be a real problem when dealing with limited resources such as database connections, sockets, file handles, and the likes.
  • No-throw Guarantee, in which case a method guarantees that it will handle all thrown exceptions locally and it will not raise them to the caller, at the same time assuring the consistency of the program's state. This type of exception safety is necessary in certain cases in C++ code, but I haven't found any compelling reason to use it in C#. Thus the focus of this article will be on the strong exception safety guarantee.

In both the strong and the basic guarantee, the developer might choose to wrap thrown exceptions in application-specific ones before propagating them to the caller. But note that the .Net documentation suggests that it is usually better to propagate built-in exceptions directly to the caller without wrapping them.

Exceptions In Action: An Example

Let's assume that you are developing an instant messaging application. Each user is represented by a User class. Each user has a list of bodies that are stored both locally on the client and on the messaging server. The server database is represented by a ServerDB class that acts as a facade, hiding the gory details of updating the server.

The code for the ServerDB class might look like the following:

class ServerDB
{
    .
    .
    .
    public static void AddBuddy( User theUser, User buddy )
    {
        .
        .
        .
    }
    .
    .
    .
}
        

While the User class might look like the following

public class User
{
    // The SetCollection is a hypothetical container resembling
    // the System.Collections.Dictionary class, except that it
    // only stores keys, but not values. Similar to std::set
    // in C++
    private SetCollection m_buddies;
    .
    .
    .
    public void AddBuddy( User buddy )
    {
        m_buddies.Add( User );
        ServerDB.AddBuddy( this, buddy );
    }
}
        

SetCollection.Add might throw an exception if we attempt to add a buddy that already existed in the collections, or it might throw an exception if it was unable to allocate enough memory (unlikely in a garbage-collected environment, yet still a possibility.) ServerDB.AddBuddy might throw an exception for several reasons, such as not being able to connect to the remote server. Although this seems to be a very remote possibility, do keep in mind that this is meant to be a trivial example. The example might be more realistic if we assume that SetCollection would attempt to persist its state to an external file. In such a case, the probability of SetCollection.Add throwing an exception would increase drastically.

The code snippet above upholds the strong exception safety guarantee if SetCollection.Add throws. But if the ServerDB.AddBuddy throws, the in-memory copy of the buddies list would be inconsistent with the server.

A better attempt might be something like this:

    public void AddBuddy( User buddy )
    {
        m_buddies.Add( buddy );
        try
        {
            ServerDB.AddBuddy( this, buddy )
        }
        catch( Exception ex )
        {
            m_buddies.Remove( buddy );
            throw ex;
        }
    }
        

This works fine. The code upholds the strong exception safety guarantee at the cost of increased code size and, most importantly, reduced readability. The purpose of the code is obscured a little by the exception handling code. I trust that you could imagine the situation if the method was more complex than this trivial two-liner.

A Better Solution: The using Statement

As you recall from your favorite C# textbook, the using keyword performs two very different functions based on its context: it is used to import namespaces into the current compilation unit, and it is also used in conjunction with the IDisposable interface to guarantee proper clean up of resources at the end of a code block.

For example, suppose that we have a class ResourceWrapper that implements IDisposable and wraps a limited resource that must be closed as soon as possible. Client code using such a class might look like the following (the example is taken directly from the MSDN library):

class ResourceWrapper
    : IDisposable
{
    .
    .
    .

    public void Dispose()
    {
        // clean up code
    }
}

class myApp
{
   public static void Main()
   {
      using (ResourceWrapper r1 = new ResourceWrapper())
      {
         .
         .
         // some code
         .
         .

         r1.DoSomething();
      }
   }
}
        

No matter how the code exits the using block, whether through an exception or a normal return, ResourceWrapper.Dispose will always get called. Such behavior upholds the strong exception gaurantee quite nicely, and it can be a good starting point to a solution to our problem.

Back to our original example, the using directive and the IDisposable interface combo don't work well for our situation. Remember that we want some sort of clean up action to take place only in the presence of exceptions. Also keep in mind that it's unlikely that we would be able to change the definition of SetCollection to support IDisposable, since doing so would drastically alter the usage semantics of the class. We could, however, implement a helper class to do the clean up on behalf of SetCollection. We'll call this class BuddyInserter, and we'll define it as follows:

public class BuddyInserter
    : IDisposable
{
    private bool            m_disposed = false;
    private bool            m_dismissed = false;
    private User            m_insertedBuddy = null;
    private SetCollection    m_theCollection = null;

    public BuddyInserter( SetCollection theCollection, User buddy )
    {
        m_insertedBuddy = buddy;
        m_theCollection = theCollection;
    }

    ~BuddyInserter()
    {
        Dispose( false );
    }

    public void Dispose()
    {
        Dispose( true );
        GC.SuppressFinalize( this );
    }

    protected void Dispose( bool disposing )
    {
        // Make sure that we are not disposed already
        if ( m_disposed == false )
        {
            // If we are NOT being called from the finalizer,
            // then we should release all resources, managed
            // and unmanaged. But we are not holding any
            // unmanaged resources
            if ( disposing )
            {
                // Check to see if rollback is needed
                if ( m_dismissed == false )
                {
                    try
                    {
                        m_theCollection.Remove( m_insertedBuddy );
                    }
                    catch
                    {
                        // Do nothing
                    }
                }
            }

            m_disposed = true;
        }
    }

    // Supress rollback action
    public void Dismiss()
    {
        m_dismissed = true;
    }
}
        

You might notice that the implementation of the protected Dispose method is a little verbose. But it follows the guidelines of the MSDN documentation to the letter. The BuddyInserter class holds the information necessary for it to rollback the operation if and only if the Dismiss method doesn't get called before Dispose. In our example, we would use this class in the following way:

public class User
{
    .
    .
    .
    public void AddBuddy( User buddy )
    {
        m_buddies.Add( buddy );
        using ( BuddyInserter inserter =<BR>		new BuddyInserter( m_buddies, buddy ) )
        {
            ServerDB.AddBuddy( this, buddy );
            inserter.Dimiss();
        }
    }
}
        

Now the code above is both simpler and cleaner than the previous attempt. If an exception is thrown from SetCollection.Add, the state remains consistent and the exception propagates to the caller without any side effects. If an exception is thrown from ServerDB.AddBuddy, the Dispose method of BuddyInserter will rollback the collection to a consistent state with the server database.

But still, the above solution is a minor improvement in terms of readability, and hand crafting a class like BuddyInserter each and every time your run into a similar situation is a daunting task that will lead to more code bloat. It's obvious that this solution is not practical, so the ever pressured programmer is likely to revert back to the following solution:

    public void AddBuddy( User buddy )
    {
        m_buddies.Add( User );
        ServerDB.AddBuddy( this, buddy );
    }
        

And we are back to square one again. But there's still hope yet.

A Practical Solution

Using reflection and two helper classes, we can attain a solution that is both elegant and practical. We'll start by defining a simple collection of IDisposable objects:

    public class ScopeGuard
        : IDisposable
    {
        private bool m_disposed = false;
        private Stack m_disposables = new Stack();

        public ScopeGuard()
        {
        }

        ~ScopeGuard()
        {
            this.Dispose( false );
        }

        // Begin IDisposable implementation
        public void Dispose()
        {
            this.Dispose( true );
            GC.SuppressFinalize( this );
        }

        protected void Dispose( bool disposing )
        {
            if ( m_disposed == false )
            {
                if ( disposing == true )
                {
                    // do managed resources clean up here
                    while ( m_disposables.Count != 0 )
                    {
                        IDisposable disposableObject
                            = (IDisposable) m_disposables.Pop();

                        disposableObject.Dispose();
                    }
                }
                m_disposed = true;
            }
        }
        // End IDisposable implementation


        public void Add( IDisposable disposableObject )
        {
            Debug.Assert( disposableObject != null );

            m_disposables.Push( disposableObject );
        }
    }
        

The ScopeGuard has only one method of its own; Add, which takes an object implementing IDisposable and stores it into a stack collection. The Dispose method simply pops the IDisposable objects off the stack and calls their corresponding Dispose methods. The use of a stack to store the objects is crucial here, since we must guarantee that objects are disposed in reverse order of their addition.

Using this class with the BuddyInserter class that we defined earlier greatly enhances the readability of the code:

    public void AddBuddy( User buddy )
    {
        using ( ScopeGuard guard = new ScopeGuard() )
        {
            m_buddies.Add( buddy );
            BuddyInserter inserter = new BuddyInserter( m_buddies, buddy );
            guard.Add( inserter );
            ServerDB.AddBuddy( this, buddy );
            inserter.Dimiss();
        }
    }
        

In the above code, exiting the using block will call ScopeGuard.Dispose, which in turn will call BodyInseter.Dispose. BodyInseter.Dispose will either undo the insertion of the buddy or do nothing at all, depending on whether BuddyInserter.Dismiss was called or not.

But still, we would have to write our own BuddyInserter and such classes whenever we find ourselves in need of commit-or-rollback behavior. It would be nice if we could somehow write a generic object that would be able of storing a pointer to a method, an object on which to call that method, and a list of arguments, and have the object exhibit the same semantics of the BuddyInserter class above.

Delegates may come to mind as a possible solution. But you'll soon find them of little use, since you can't guarantee that the clean up methods you might need to call will always have the same signature. After some research, the only practical solution that I could find relies on reflection.

We'll need one more helper class: ObjectGuard:

    public class ObjectGuard
        : IDisposable
    {
        private MethodInfo    m_methodInfo = null;
        private object        m_target = null;
        private object[]    m_methodArgs = null;
        private bool        m_disposed = false;
        private bool        m_dismissed = true;

        public static ObjectGuard Make( object obj, string methodName,<BR>		object[] methodArgs )
        {
            Debug.Assert( obj != null );
            Debug.Assert( methodArgs != null );

            Type objType = obj.GetType();

            Type[] argsTypes = new Type[ methodArgs.Length ];

            for ( int i = 0; i < methodArgs.Length; ++i )
            {
                argsTypes[i] = methodArgs[i].GetType();
            }

            MethodInfo methodInfo = objType.GetMethod( methodName,<BR>		argsTypes );

            Debug.Assert( methodInfo != null );

            return new ObjectGuard( obj, methodInfo, methodArgs );
        }


        private ObjectGuard( object target, MethodInfo methodInfo,<BR>		object[] methodArgs )
        {
            m_target        = target;
            m_methodInfo    = methodInfo;
            m_methodArgs    = methodArgs;
            m_dismissed        = false;
        }

        ~ObjectGuard()
        {
            Dispose( false );
        }

        public void Dispose()
        {
            Dispose( true );
            GC.SuppressFinalize( this );
        }

        protected void Dispose( bool disposing )
        {
            if ( m_disposed == false )
            {
                if ( disposing )
                {
                    if ( m_dismissed == false )
                    {
                        try
                        {
                            m_methodInfo.Invoke( m_target, m_methodArgs );
                        }
                        catch
                        {
                            // Do nothing
                        }
                    }
                }

                m_disposed = true;
            }
        }

        public void Dismiss()
        {
            m_dismissed = true;
        }

    }
        

Note the static factory method ObjectGuard.Make, which takes a name of the method as a string, an object to invoke the method on, and a list of arguments matching the method's signature. This method asserts that all parameters are correct and then constructs an instance of ObjectGuard class, which in implements IDisposable and follows the same semantics of the BuddyInserter class the we have seen earlier. Using this class and ScopeGuard, our AddBuddy example becomes something like the following:

    public void AddBuddy( User buddy )
    {
        using ( ScopeGuard guard = new ScopeGuard() )
        {
            m_buddies.Add( buddy );
            ObjectGuard inserterGuard
                = ObjectGuard.Make( m_buddies, "Remove",<BR>			new object[] { buddy } );
            guard.Add( inserterGuard );
            ServerDB.AddBuddy( this, buddy );
            inserterGuard.Dimiss();
        }
    }
        

Save using a string to pass the method name, I believe that the above code is more elegant and more practical than the usual try, catch and finally triad. Of course, there will be a performance hit due to the use of reflection. But I believe that when faced with a trade off between performance and exception safety, one should always favor the latter. Once you have a stable and correct application, let profiling guide you to any performance bottlenecks, and then optimize. Remember that (premature) optimization is evil.

Another Example: Migrating Your Old Exception Handling Code

You must have written something resembling the following code snippet at one time or another:

    public void InsertBuddy( User theUser, User buddy )
    {
        SqlConnection conn = null;
        SqlTransaction trx = null;

        try
        {
            conn = new SqlConnection( ... );
            conn.Open();
            trx = conn.BeginTransaction();

            // do some DB manipulation

            trx.Commit();
        }
        catch( Exception ex )
        {
            trx.Rollback();
            throw ex;
        }
        finally
        {
            conn.Close();
        }
    }
        

For the trained eye, this code is exception-safe. But the intent is obscured a little by the exception handling code, and the magic of the finally block looks--to me at least--very intimidating.

Writing the above code snippet using ScopeGuard and ObjectGuard looks a lot better in terms of both readability and maintainability:

    public void InsertBuddy( User theUser, User buddy )
    {
        using ( ScopeGuard guard = new ScopeGuard() )
        {
            SqlConnection conn = new SqlConnection( ... );
            conn.Open();

            guard.Add( ObjectGuard.Make( conn, "Close", new object[] {} );

            SqlTransaction trx = conn.BeginTransaction();
            ObjectGuard trxGuard
                = ObjectGuard.Make( trx, "Rollback", new object[] {} );

            guard.Add( trxGuard );

            // do some DB manipulation

            trx.Commit();
            trxGuard.Dismiss();
        }
    }
        

Please note that we didn't hold onto a reference to the ObjectGuard calling the SqlConnection.Close method, since we want the clean up action to be performed regardless of how we exit the code block.

Conclusion

It is my belief that exception safety is often a neglected topic among programmers. And my own personal experience has taught me that such negligence always comes back to bite you someday. But using the solution outlined above, I'm finding myself doing the right thing and totally enjoying it. I hope you'll give this approach a try. Your comments and suggestions are greatly appreciated.

Acknowledgments

The idea of this article came from an article by Andrei Alexandrescu and Petru Marginean published on the CUJ's experts' forum. The method that the aforementioned authors present, while done in C++, is far more superior and elegant than anything I might attempt to write.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

MohammadAbdulfatah
Web Developer
Saudi Arabia Saudi Arabia
Member
Mohammad Abdulfatah is currently working as a senior software developer in a small software shop where he spends most of his time maintaining tons of C++/Win32 code and writing .Net web applications. He hates having his picture taken for the same reason he freaks out when he hears his own recorded voice: they both don't look/sound like his own self-image/voice. When he is not coding for a living he could be found stuck to his computer at home coding for fun, reading a book, writing on his weblog (http://mohammad.abdulfatah.net/), or pursuing other vanity projects.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generalguard.Add(trxGuard) missingsussAnonymous18 Mar '03 - 20:44 
Isn't your last sample code section missing a call to:
 
guard.Add(trxGuard);

GeneralRe: guard.Add(trxGuard) missingmemberExquisitor18 Mar '03 - 21:47 
You are correct. Thanks for the correction. I'll repost the article with this and other corrections to both article and source code before the end of the day.
Generalrethrowing an exceptionmemberMaximilian Hänel17 Mar '03 - 22:33 
Hi,
 
first of all thanks for this great article!
 
In your code snippets you often write code like that
catch( Exception ex )
{
   //...
   throw ex;
}
wich actually throws a new exception with the same exception object. The downside is that you are loosing the point where the exception originally has been thrown (-> stack trace). A better approach would be to write a simple throw statement without the ex reference specified:
catch( Exception ex )
{
   //...
   throw; //
}
This rethrows the exception and preserves the stack trace of the exception.
 
cu
 
Max

 
"You can always improve your chances of writing
bug-free code by writing code that doesn't do anything"

Rob Macdonald, Serious ADO

GeneralRe: rethrowing an exceptionmemberExquisitor18 Mar '03 - 9:32 
Maximilian Hänel wrote:
first of all thanks for this great article!
 
And I thank you in return for your kind words.
 

Maximilian Hänel wrote:
A better approach would be to write a simple throw statement without the ex reference specified:
catch( Exception ex ){ //... throw; //}
 
This rethrows the exception and preserves the stack trace of the exception.

 
This is embarrassing for me to admit, but I didn't know that the previous syntax is valid. I thought it would be valid only if you had an empty catch statement, as in
catch
  {
     throw;
  }
So, thanks for the tip. But I hope that you agree with me that there are many such details to watch out for when handling exception, to the point of making the method outlined in this article more desirable, even preferred to explicit excpetion handling.
 

GeneralRe: rethrowing an exceptionmemberJim Stone19 Mar '03 - 6:23 
I'm not sure if exception handling in C# differs radically from Java, but I suspect it is much the same. Among Java programmers, there is a common misunderstanding about how/when the stack trace associated with an exception object instance is generated. In Java, rethrowing an exception like this:
 
catch ( Exception e ) { throw e; }
does NOT lose the original stack trace of the exception e. The stack trace for e was actually generated at the time that exception object instance (referenced by e) was constructed. Rethrowing the same exception instance will not destroy its original stack trace.
 
If someone would like to confirm this behavior in C# (I don't have Visual Studio handy), I'd be interested to hear about the results. You can use this Java program to test the exception handling in C# (provided that you translate it to C# syntax).
 
public class Test {
    public static void main( String[] args ) {
        try {
            method1();
        } catch ( Exception e ) {
            System.out.println( "Stack trace after rethrow" );
            e.printStackTrace();
        }
    }
    
    public static void method1() throws Exception {
        try {
            method2();
        } catch ( Exception e ) {
            throw e;
        }
    }
    
    public static void method2() throws Exception {
        Exception e = new Exception( "Exception created in method2()" );
        System.out.println( "Stack trace before throw" );
        e.printStackTrace();
        throw e;
    }
}
 
The resulting stack trace in Java is:
 
Stack trace before throw
java.lang.Exception: Exception created in method2()
        at Test.method2(Test.java:20)
        at Test.method1(Test.java:13)
        at Test.main(Test.java:4)
Stack trace after rethrow
java.lang.Exception: Exception created in method2()
        at Test.method2(Test.java:20)
        at Test.method1(Test.java:13)
        at Test.main(Test.java:4)
Try it in C#.
GeneralRe: rethrowing an exceptionmemberExquisitor19 Mar '03 - 7:24 
The best translation for your program into C# that I could manage looks like the following:
namespace StackTrace
{
  class Test
  {
    [STAThread]
    static void Main(string[] args)
    {
      try
      {
        method1();
      } 
      catch ( Exception ex )
      {
        Console.WriteLine( "Stack trace after rethrow" );
        Console.WriteLine( ex.StackTrace );
      }
    }
 
    public static void method1()
    {
      try
      {
        method2();
      }
      catch ( Exception ex )
      {
        throw ex;
      }
    }
 
    public static void method2()
    {
      Exception ex 
        = new Exception( "Exception created in method2" );
 
      Console.WriteLine( "Strack trace before throw" );
      Console.WriteLine( ex.StackTrace );
      throw ex;
    }
  }
}
Which would produce the following output:
Strack trace before throw
 
Stack trace after rethrow
   at StackTrace.Test.method1() in c:\projects\stacktracd\test.cs:line 29
   at StackTrace.Test.Main(String[] args) in c:\projects\stacktracd\test.cs:line
 12
Modifying it to:
namespace StackTrace
{
  class Test
  {
    [STAThread]
    static void Main(string[] args)
    {
      try
      {
        method1();
      } 
      catch ( Exception ex )
      {
        Console.WriteLine( "Stack trace after rethrow" );
        Console.WriteLine( ex.StackTrace );
      }
    }
 
    public static void method1()
    {
      method2();
    }
 
    public static void method2()
    {
      Exception ex 
        = new Exception( "Exception created in method2" );
 
      Console.WriteLine( "Strack trace before throw" );
      Console.WriteLine( ex.StackTrace );
      throw ex;
    }
  }
}
Produces the following output:
Strack trace before throw
 
Stack trace after rethrow
   at StackTrace.Test.method2() in c:\projects\stacktracd\test.cs:line 38
   at StackTrace.Test.method1() in c:\projects\stacktracd\test.cs:line 25
   at StackTrace.Test.Main(String[] args) in c:\projects\stacktracd\test.cs:line
 12
So, yes, apprently rethrowing an exception resets the stack trace in C#
GeneralRe: rethrowing an exceptionmemberLockias2 Apr '03 - 19:13 
So, yes, apprently rethrowing an exception resets the stack trace in C#
 
No, it does not. It does using the method you used:
 
throw ex;
 
but it does not using the method stated by first post of this thread:
 
throw;

GeneralRe: rethrowing an exceptionmemberExquisitor6 Apr '03 - 23:04 
If you would be kind enough to read the post by Jim Stone, you would notice that our discussion was on the behavior of the first throw usage, not the second one.
 
To rehash, using code like

throw ex

in Java, doesn't cause the stack trace to be reset, where in C#, it does.
 
Thanks for your input, nevertheless.
GeneralSome correctionsmemberleppie14 Mar '03 - 7:42 
Hi
 
Nice article, but code needs some corrections:
 
1. Sample code lacks finishing brace (how did you compile?).
2. That try catch finally block wont compile either. Variables need to be declared outside the block.
 
One question: so if I use using, and an exception is thrown inside the using block, do i need to check for exceptions? Or will they be silent (caught by the using block)?
 
CHeers Smile | :)
 
I rated this article 2 by mistake. It deserves more. I wanted to get to the second page... - vjedlicka 3:33 25 Nov '02
GeneralRe: Some correctionsmemberExquisitor14 Mar '03 - 8:18 
As to the corrections, I thank you. And you are indeed correct on both accounts. I use both ScopeGuard and ObjectGuard in a larger ditributed application. And for some reason that I cannot fathom, the version that I have posted is not the same as the one I have in source control. I believe it's quite easy for anyone to get the code to compile, but if you think I should post the corrected code, then I'd be more than happy to do so.
 
As to the SqlTransaction example, you are correct again. But I hope that the intent of the code is still clear enough.
 
As to your question, you are not meant to catch any thrown exceptions using this technique. Is it assumed that any exceptions will be handled by the caller, which is, as far as my experience shows, is the most common scenario. The solution presented here is meant to ensure that your code still guarantees the correctness of the program state in the odd event of an exceptoin.
 
And cheers to you too, my fine sir Big Grin | :-D
GeneralRe: Some correctionsmemberExquisitor19 Mar '03 - 7:29 
I have posted the corrections that you have mentioned, and others, to CodeProject. I hope they'll get them in as soon as possible.
 
Now, is there any chance of you recosnidering your harsh vote of two? Smile | :)
GeneralRe: Some correctionsmemberleppie19 Mar '03 - 9:14 
Exquisitor wrote:
Now, is there any chance of you recosnidering your harsh vote of two?
 
If I had to give you a vote of 2, your rating would go way down. Cool | :cool: My sig was a message to one of my articles Poke tongue | ;-P
 
PS: if you didnt gather that, it means I havent voted for this article (yet) Poke tongue | ;-P
 
I rated this article 2 by mistake. It deserves more. I wanted to get to the second page... - vjedlicka 3:33 25 Nov '02
GeneralRe: Some correctionsmemberExquisitor19 Mar '03 - 10:40 
Forgive me. I do stand corrected. But someone did give me a rather low vote at the begining, and it was only logical to assume it was you. Confused | :confused:
GeneralOverheadmemberDeyan Petrov13 Mar '03 - 21:32 
I believe your technique will add constant overhead to the execution of the code, whereas standard exception handling adds overhead only in case an exception is really thrown ... I refer to the instantiation and using of ScopeGuard and ObjectGuard in the flow of the program
 
Best regards,
Deyan Petrov
GeneralRe: OverheadmemberExquisitor14 Mar '03 - 1:48 
You are absolutely correct, I'm afraid. But I tend to think that whatever (little) overhead this technique might incur is well-justified. Besides, judging from my C++ experience, using exceptions adds a constant runtime overhead regardless of whether exceptions are thrown or not. And since there is no way to turn off exceptions in a C# program--in contrast to native C++ code--that overhead is always there.
GeneralRe: OverheadmemberPeter Gummer25 Mar '03 - 15:27 
I agree that overhead is usually less important than having simpler, easier-to-understand code.
 
But I disagree that your technique achieves this. The code using try...catch...finally is no more complex, and, to my eyes, much easier to understand than your technique. Any C# programmer, other than a complete novice, understands at a glance what the try...catch...finally code is doing; indeed, it is perfectly legible by programmers used to other languages like Java and Delphi.
 
To understand the code written using your technique, on the other hand, requires learning about the two helper classes. Given that they don't actually reduce the amount of code, I don't see why anyone would bother using such a non-standard technique.
GeneralRe: OverheadmemberExquisitor25 Mar '03 - 19:35 
As far as readability is concerned, I think it's largely a matter of taste. Even my own team members are split on the subject. But I think there are other more subtle issues to consider.
 
You're absolutely correct when stating that almost every programmer is familiar with the use of try, catch and finally. And most are able to understand code using the standard exception handling mechanism without breaking a sweat. But the same argument can be applied to concurrent programming techniques; every novice programmer can easily understand the concepts of mutexes, locks, and other synchronization primitives. But it takes a lot of experience, and a lot of core dumps and crashes, to master their use.
 
The same applies to exceptions and exception handling, albeit to a lesser extent. Understanding the implications of throwing an exception or handling one on the program's flow, and accounting for that to ensure that the program maintains a proper state, and maintaining the correctness of the code as it evolves, is quite a tall order on any programmer, novice or otherwise. A better approach would be to program defensively and to write code that is able to recover gracefully from exceptions regardless of when or where they are thrown. And that is, in my opinion, the real value of this technique.
 
Taking the C++ language as another example, I would classify C++ as a very mature language, and indeed most professionals working with it are the among the industry's elite. Yet, five years after its standardization, exception handling techniques and strategies are still being discussed and investigated all the time (go to the CUJ's experts forum to better understand what I mean). This goes to show that exception handling is not as easy or as safe as we wish it to be.
GeneralRe: OverheadmemberAndy Smith2 Apr '03 - 9:42 
Exquisitor wrote:
Besides, judging from my C++ experience, using exceptions adds a constant runtime overhead regardless of whether exceptions are thrown or not.
 
you shouldn't judge c# from your c++ experience.
try/catch/finally has "no" overhead when exceptions don't occur.
I realize this is different than c++, and is generally hard for c++-background people to believe.
 
Do a test yourself to see.

GeneralRe: OverheadmemberExquisitor3 Apr '03 - 12:15 
I beg to differ. You claim that there's no overhead from exceptions in C#, but I think it would be more correct to assume that the overhead is always there, rather than not present at all. I can't test it because there's no way to disable excpeiton handling in C#.
 
And you would have to forgive old dinosaurs such as myself for our fixation on performance and overhead Smile | :)
GeneralRe: OverheadmemberMark Smithson6 Apr '03 - 9:45 
Firstly, a great article. Really useful for handling transactional code, I can see an application in one of my current projects. This uses the object persistence framework "bamboo.prevalence" that does not inherently support transactions.
 
Secondly, I believe some simple refectoring could reduce the 'normal' run-time impact.
 
The ObjectGurad could be modified to take the methodName instead of the method info. The reflection code in the Make function could then be invoked if (when) an exception occurs and the function needs to be called. During normal execution the overhead of reflection will be avoided.
 
There is a risk that invaild method names may being passed that would not easily picked up during development. Perhaps a compile switch could be used, to enable/disable checking of the method name.
 
Another way that the overhead could be avoided is by the client code caching the MethodInfo for the functions that will be 'guarded'.
 
Regards
 
Mark Smithson

GeneralRe: OverheadmemberExquisitor16 Apr '03 - 3:27 
Excellent ideas. I'll see if I can implement your suggested optimizations in release buids while keeping the current behavior in debug builds. Keep a lookout for the next update!

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 2 Apr 2003
Article Copyright 2003 by MohammadAbdulfatah
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid