Unhandled Exception by a "throw new..", what's best practice? It's already handled

18,100

Solution 1

If you throw an exception in your code, you need to catch it and do something with it - if you don't, you have not handled it.

If you throw within a catch block, the same thing applies. You have thrown an exception which will keep propagating till a suitable catch block has been found. If non exists, it is unhandled.

You need to structure your higher level (UI) code so it catches the right types of exceptions and communicates the information you want back to the user:

try
{
  // code that can throw 
}
catch(VerySpecificException ex)
{
  // communicate to user details about VerySpecificException. 
  // possibly log.
  // Do not re-throw or throw a new excpetion as it is now handled. 
}
catch(AnotherSpecificException ex)
{
  // communicate to user details about AnotherSpecificException. 
}
catch(LessSpecificException ex)
{
  // communicate to user details about LessSpecificException. 
}
catch(EveLessSpecificException ex)
{
  // communicate to user details about EvenLessSpecificException. 
}

Solution 2

You need to understand how and when to catch exceptions.

The nasty thing with throwing exceptions in (worker) threads is that any top-level exception handler (such as a try/catch in program.cs) will not catch and log the exceptions thrown in threads. Hence you should always have a general try/catch in the thread entry method, at least if you do not want your application to die.

A pretty simply rule is that you should only catch exceptions that you can handle to deliver the expected result from a method. And at entry point to prevent the application from dying (but sometimes it's better to let the application die).

To understand exceptions better, you might want to read my blog articles about exceptions: http://blog.gauffin.org/tag/exceptions/

Solution 3

A throw does not handle an error but it raises one. Without a throw there is no error to handle.

You handle an exception by catching it. You need a try - catch block somewhere in your code which calls GetVersion (or somewhere in the code which calls the code that calls GetVersion etc.). If you don't catch the UnexpectedQueryException in your call hierarchy, it is unhandled and your application will stop.

An example which calls GetVersion different times (without handling exceptions).

List<SomeObject> GetAllVersions(byte[] bytes)
{
    var result = new List<SomeObject>();

    foreach (byte b in bytes)
    {
        result.Add(GetVersion(b));
    }

    return result;
}

Now it's up to you where to handle the exception. You could do it inside the loop, so that you get a result, containing all the successfully retrieved objects:

foreach (byte b in bytes)
{
    try
    {
        result.Add(GetVersion(b));
    }
    catch (UnexpectedQueryException e)
    {
        // this is where your exception handling starts
        // display an error, log the exception, ...
    }
}

Or you can handle the exception at another level of your application, e.g. wrap the call to GetAllVersions into a try-catch block:

List<SomeObject> = null;
try
{
    versionList = GetAllVersions(bytes)
    // do something with versionList
}
catch (UnexpectedQueryException e)
{
    // this is where your exception handling starts
    // display an error, log the exception, ...
    // Note that versionList will be null in error case
}

This is the main advantage of exceptions. They propagate throughout the call stack. So you don't need to handle it in the line of code after the error, but somewhere in your application where you think it's appropriate.

Share:
18,100
Independent
Author by

Independent

Focused on IT solutions, integrations since beginning of 2000. Started .NET and MSSQL technologies at the release in between .NET 3.0 and 3.5. Later oriented around the strategic and also analysis aspects on IT.

Updated on June 28, 2022

Comments

  • Independent
    Independent almost 2 years

    I try to put a exception logic which a part of a system can fall back to on unexpected behaviors.

    The work should be done of a new class that inherits Exception object and extend the functionality with a new "exit" which consist of a error-signal to the user and a logging routine.

    I may need to understand the use of throw better, but I though I could make it fairly transparent by i.e. this:

    public SomeObject GetVersion(byte p)
    {
        switch ((SomeObject)p)
        {
            case Version.SomeType1:
                ...
                break;
            case Version.SomeType2:
                ...
                break;
            default:
                throw new UnexpectedQueryException(this.someOtherObject, errorCode);
        }
        return (SomeObject)p;
    }
    

    I think you can see what I'm trying to do here.

    I try to throw when the application can't serve the request. The throw are meant to put the execution through the exception (which generates a adequate error code to caller). This example is a error of type "I know you gived me a 9 but only 1-8 is allowed here)", which errorCode sends further to the UnexpectedQueryException(...).

    Unfortunately the application take the throw as unhandled and closes my Thread and application won't operate until restart. Beside this scenario i'm also use this throw in catch statements.

    In my eyes, this is Very handled.

    What best practice here?
    I want the exception handling to be a "fall back" to activate on different scenarios (like above) so I always have an easy way to communicate an error back to the user (which mean I can send very exact info about where the exception is).

    Also i, Of Course, want the application to continue working.

    A part of code from the Exception logic,

    public class UnexpectedQueryException: CommunicationException
    {
        public UnexpectedQueryException(SomeObject object, ErrorCode errorCode) : base("UnexpectedQueryException", object, errorCode)
        {
         .........
        }
    }
    

    Which, in turn, inherits the base Exception object,

    public class CommunicationException : Exception
    {
        ..some fields..
    
        public CommunicationException(string Message, SomeObject object, ErrorCode errorcode)
        {
         .....
        }
        public CommunicationException() : base("CommunicationException")
        { }
    }