Catching Common Exception Handling Mistakes

by Chad 18. January 2011 11:10

Microsoft provides excellent guidance for exceptions, but it's easy to forget and make some of these common exception handling mistakes. Below is a list of "must remember" exception handling guidance when programming in C# (although most of this is also applicable to other .NET languages.)

When to Catch Exceptions?

Only catch an exception when you understand exactly why it will be thrown and can recover from it.

If you follow this one rule, it will prevent many of the problems that you can get into when handling exceptions.  Most of the time, you can find a list of exceptions that a member will throw from the member's XML documentation. You can access this documentation via Intellisense or by hovering the mouse cursor over the member. For detailed documentation, you can often see a list of exceptions along with the specific condition that will throw the exception on the member's MSDN documentation page.

This may feel funny at first, but remember that exceptions aren't bad. Understanding when and why a specific exception will be thrown will create more stable and secure code. If your application crashes because of an unhandled exception, that's just a signal that you forgot to program for a specific condition. So, before typing “catch” answer both of these questions:

  1. Do I know exactly why this exception is being thrown here?
  2. Can I recover from this exception?

 

Do not catch System.Exception
You should never catch System.Exception (or System.SystemException,) unless you plan to log and immediately re-throw the exception. Because all managed exceptions ultimately inherit from System.Exception, you cannot possibly know exactly why the exception you’re catching is being thrown. You should always catch the most specific exception type that you can.

If you do succumb to the temptation of catching System.Exception and are able to repress the shame from such coding Smile do be sure to use “catch(Exception) {…}” NOT “catch {…}”. A catch statement without an exception type will catch all exceptions, including non-CLS exceptions.

"throw;" != "throw err;"
If you catch an exception for logging or other reasons, but then need to re-throw the exception, ALWAYS use "throw;". "throw err;" will affect the stack trace making troubleshooting more difficult. Look at the following call stacks and sample code for an example of the problem that "throw err;" causes.

// With throw err;
//at MyApp.Program.Method1() in ...\Program.cs:line 29
//at MyApp.Program.Run() in ...\Program.cs:line 18
//at MyApp.Program.Main(String[] args) in ...\Program.cs:line 13
class Program
{
  static void Main(string[] args)
  {
    Program p = new Program();
    p.Run();
  }

  void Run()
  {
    this.Method1();
  }

  void Method1()
  {
    try { Method2(); } catch (Exception err) { throw err; }
  }

  void Method2()
  {
    try { Method3(); } catch (Exception err) { throw err; }
  }

  void Method3()
  {
    throw new InvalidOperationException();
  }
}
// With throw;
//at MyApp.Program.Method3() in ...\Program.cs:line 33
//at MyApp.Program.Method2() in ...\Program.cs:line 28
//at MyApp.Program.Method1() in ...\Program.cs:line 23
//at MyApp.Program.Run() in ...\Program.cs:line 18
//at MyApp.Program.Main(String[] args) in ...\Program.cs:line 13
class Program
{
  static void Main(string[] args)
  {
    Program p = new Program();
    p.Run();
  }

  void Run()
  {
    this.Method1();
  }

  void Method1()
  {
    try { Method2(); } catch (Exception) { throw; }
  }

  void Method2()
  {
    try { Method3(); } catch (Exception) { throw; }
  }

  void Method3()
  {
    throw new InvalidOperationException();
  }
}

Tags:

.NET-Basics

Event Handler Memory Leaks

by Chad 9. February 2010 06:18

Event handlers are a common cause of memory leaks in managed applications. It’s so easy to register an event handler, that sometimes we can forget what’s actually happening. There are three parties involved in eventing: the event source, a delegate, and the event sink.

The event source is the object that publishes notifications via an event. The event sink is the object that is interested in those notifications and knows how to respond to the event. The delegate is the object that enables the event source to communicate with the event sink.

Looking at the System.Delegateclass, we see that it has two properties: Target and Method. Target contains a reference to the event sink object and Method contains a MethodInfo object used to invoke the event handler method on the event sink object. When you use the C# statement eventSource.SomeEvent += new EventHandler(eventSink.SomeEventHandler); you are creating a new delegate with a reference to your event sink object and adding a reference to the delegate class to the event source object. The references look like this: event source > delegate > event sink.

The effect of this isn’t very visible when the lifetime of the event source and event sink are similar. However, when the event source lives much longer, say for the lifetime of the application, and the event sink only has a short lifetime, you can quickly leak memory because the event source will never release it’s reference to the event sink.

Consider this example

class View

{

    private string _name;

    public View(string name)

    {

        _name = name;

 

        // Register for CollectionChanged notifications; MASTER_COLLECTION

        // is static.

        Program.MASTER_COLLECTION.CollectionChanged +=

            new NotifyCollectionChangedEventHandler(

                masterCollection_CollectionChanged);

    }

 

    void masterCollection_CollectionChanged(object sender,

        NotifyCollectionChangedEventArgs e)

    {

        // Update view

        Console.WriteLine("{0}: {1} items.",

            _name,

            Program.MASTER_COLLECTION.Count);

    }

 

    ~View()

    {

        Console.WriteLine("View {0} Finalized.", _name);

    }

}

 

class Program

{

    public static readonly ObservableCollection<object> MASTER_COLLECTION

        = new ObservableCollection<object>();

 

    public void Run()

    {

        // Create two views

        View v1 = new View("v1");

        View v2 = new View("v2");

 

        // Raise CollectionChanged event

        MASTER_COLLECTION.Add(new object());

 

        // Release v1 & v2 references

        v1 = null;

        v2 = null;

 

        // Wait for Garbage collector to release memory

        GC.Collect();

        GC.WaitForPendingFinalizers();

 

        // Create v3

        View v3 = new View("v3");

 

        // Raise CollectionChanged event

        Console.WriteLine("We only expect v3 to be in memory.");

        MASTER_COLLECTION.Add(new object());

        v3 = null;

 

        // Wait for Garbage collector to release memory

        GC.Collect();

        GC.WaitForPendingFinalizers();

 

        Console.WriteLine("Example finished.");

        Console.ReadLine();

    }

 

 

    static void Main(string[] args)

    {

        Program p = new Program();

        p.Run();

    }

}

The output for this is:

v1: 1 items.
v2: 1 items.
We only expect v3 to be in memory.
v1: 2 items.
v2: 2 items.
v3: 2 items.
Example finished.
View v3 Finalized.
View v1 Finalized.
View v2 Finalized.

How to avoid this?
You need to keep this subtle problem in mind when designing your classes. To prevent these types of memory leaks, you’ll need to design mechanisms into your object’s lifecycle so that it can detach it’s event handlers. Detaching an event handler is as simple as using the –= operator. The difficult part is knowing when to detach. You can use the IDisposable pattern or expose a CleanUp() method or add lifecycle events to trigger the detach.

Tags: ,

.NET-Basics

WCF Presentation Materials

by Chad 27. September 2009 09:37

Thank you to everyone who came to the Springfield .NET Users group meeting last Tuesday and a special thank you to PaperWise for hosting the meeting. I hope everyone found the information on WCF useful; I appreciate your questions and feedback. As promised, I'm posting my presentation slides and source code. Enjoy!

WCFPresentation_20090922.zip (949.00 kb)

Tags: , , , , ,

Presentations

Powered by BlogEngine.NET 1.5.0.7
Theme by Mads Kristensen

About the author

Chad

Meeeee!!!

Hi, my name is Chad Boschert and I'm a software developer in Springfield, Missouri. I've been developing .NET applications in C# since 2002.

Recent Comments

Comment RSS

Calendar

<<  May 2013  >>
MoTuWeThFrSaSu
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

View posts in large calendar