Click here to Skip to main content
16,016,770 members
Please Sign up or sign in to vote.
1.50/5 (2 votes)
See more:
C#
public class TestInnerException
{
    public static void Main()
    {
        try
        {
            try
            {
                throw new ArgumentException();
            }

            catch (ArgumentException e)
            {
                //make sure this path does not exist
                if (File.Exists("file://Bigsky//log.txt%22)%20==%20false) == false)
                {
                    throw new FileNotFoundException("File Not found when trying to write argument exception to the file", e);
                }
            }
        }

        catch (Exception e)
        {
            Console.WriteLine(String.Concat(e.StackTrace, e.Message));

            if (e.InnerException != null)
            {
                Console.WriteLine("Inner Exception");
                Console.WriteLine(String.Concat(e.InnerException.StackTrace, e.InnerException.Message));
            }
        }
        Console.ReadLine();
    }
}
Posted
Comments
R Hemanth 20-Apr-15 14:38pm    
Will u please give an example fir inner exceptions without using multiple try blocks ...using class of other assembly which as one method
Sergey Alexandrovich Kryukov 20-Apr-15 18:38pm    
I have you an example. Please don't re-post, this is considered as abuse. If you have problem with some of the answers, you can always ask some follow-up questions on the same page.
—SA

It's good to do in many cases, but not the way you do it. Re-throwing is done to replace abstract, generic, "system-universal" exceptions with some more application-specific and concrete. For example, in the case of file-not-found condition, you could create your exception type which specifies the name of the file, explains the user the purpose of having this file and suggests the steps to fix the problem. The exception data can include file name and perhaps some classified information.

Why so? Because you should not catch exception too locally. You need to handle exception at the places where you have all you need to handle them in a useful way. I call them "competency points". At such point, you may want to handle exception thrown not only in the given line, but in some others. You would need to have a handle working specifically with the exception type you created. It's a common mistake to rely exclusively on the application message; a part of very sorrowful present-data fallacy of trying to work with strings representing data, instead of data.

—SA
 
Share this answer
 
Comments
Sascha Lefèvre 20-Apr-15 20:12pm    
My 5.
Sergey Alexandrovich Kryukov 20-Apr-15 21:48pm    
Thank you, Sascha.
—SA
Your code-sample:

Done right:
When throwing the FileNotFoundException you include the ArgumentException as an inner exception.

Could be done better:
You could include the name of the file that could not be found by using this constructor instead:
C#
public FileNotFoundException(string message, string fileName, Exception innerException)

(Please also refer to solution 2)


Some general rules for Exception-handling:
(Don't consider these points as exhaustive.)

- When throwing a new exception after catching one, put the previous exception as an inner exception into the new one. (In general.)

- When re-throwing the same exception as just caught, dont do throw ex; (because that will reset the stacktrace) but simply throw;

- Don't clutter your code with exception-handling. Only catch exceptions for these purposes: 1) Logging 2) Trying to remedy the failure 3) Re-throwing it after adding additional information about the error to it1 4) Putting it into another exception in order to provide additional information about the error1. Otherwise just let exceptions "bubble up". The only "mandatory" exception-catching would be at the top-level of your program (e.g. in the Main()-method) in order to log it. In reverse, this means:

- Don't swallow exceptions without doing anything.
(In general. There might be rare exceptions, which should be considered carefully.)

- When available, use versions of methods that don't throw an exception in case of failure but return a boolean success-flag (e.g. Int32.TryParse(..) instead of Int32.Parse(..)).

- Don't (ab)use exceptions for control-flow.
(In general. It might be o.k. locally, e.g. for re-attempting to read user-input until it is accepted. Please see the first comment below.)

- Exceptions should be exceptional. Don't throw exceptions for things that happen all the time.

1 :
The message of the exception is not the only information that an exception can carry. You can store further information about an error in other properties, e.g.:
The Data-Property[^]
The Source-Property[^]
Depending on the concrete Exception, there can be more, e.g.:
The FileName-Property[^] of FileNotFoundException
The ParamName-Property[^] of ArgumentException
And of course you can create your custom Exceptions and implement custom properties for them to carry your custom error-information.

A very good blog-post about exception-handling:
http://www.hanselman.com/blog/GoodExceptionManagementRulesOfThumb.aspx[^]

MSDN on exceptions and exception-handling:
https://msdn.microsoft.com/en-us/library/ms173160%28v=vs.110%29.aspx[^]


Edit: Incorporated suggestions from Sergey Alexandrovich Kryukov's comment below.
 
Share this answer
 
v5
Comments
Sergey Alexandrovich Kryukov 20-Apr-15 15:28pm    
Sascha,

I voted 4. I think you have some good point, but re-throwing purpose is not well explained. Yes, it's not so easy. Please see Solution 2.

Some or your advise should be clarified or come with "depending on..." kind of disclaimer. I would not try to overview all the ideas on exception handling in one Quick Answer, it hardly could be done in a comprehensive way. Even "Don't swallow exceptions without doing anything", which one of the worst things people do, has its rare exclusions. Sometimes, this is done to cover up some "bad API" call, when you don't have a way to patch that API. Using InnerException is also not a totally universal way, there are alternatives. You ignored Exception.Data, for example. Some advice need explanations. "Exceptions should be exceptional" could be a good idea if... everyone understood what it may mean.

Finally, "Don't (ab)use exceptions for control-flow" is a matter of heated discussion without clear consensus (but in all cases the developer or the team finally decide). There is no a clear-cut watershed between control flow and not control flow. I think it all depends. Implementing a lot of flow logic via exceptions is apparently bad, but consider the case where the user enters the data which is validated with the possibility of throwing an exception. I would say, there is nothing wrong with having a loop with handling the exception inside it, to let the user to fix the input and then break out of the loop. It all depends on many factors.

—SA
Sascha Lefèvre 20-Apr-15 16:12pm    
Thank you, Sergey. I agree with you, there should be some "depending on"-s ;-) I will improve it a bit later and maybe I'll have a question or two for you, if that is alright.
/Sascha
Sergey Alexandrovich Kryukov 20-Apr-15 18:04pm    
Absolutely. Will try to ask if I can as as soon as I can.
On inquirer's request, I just added Solution 3 with some illustration.
—SA
Sascha Lefèvre 20-Apr-15 18:52pm    
Are you aware of BCL-Methods which, like .Parse and .TryParse, have two "similar versions" but where the exception-throwing version could provide details about the error which you would pass up when using the bool-returning version?
Sergey Alexandrovich Kryukov 20-Apr-15 18:56pm    
Maybe not. Would you please clarify/reference them?
—SA
R Hemanth asked:

Will u please give an example of inner exceptions without using multiple try blocks ...using class of other assembly which as one method
It has nothing to do with loops. Here is one example for you:
C#
enum FilePurpose {
    InitialConfiguration,
    ExpectedConfiguration,
    ActualConfiguration,
    //...
}

internal class MyFileException : System.IO.FileNotFoundException {
    internal MyFileException(
        string fileName,
        FilePurpose purpose,
        Exception original)
    : base("File not found", fileName, original){
        this.Purpose = purpose;
    }
    internal FilePurpose Purpose { get; private set; }
}

C#
class Sample {
    void Test() {
        FilePurpose purpose = FilePurpose.ExpectedConfiguration;
        try {
            // try to open some file
        } catch (System.IO.FileNotFoundException e) {
            throw new MyFileException(e.FileName, purpose, e);
        }
    }
}

This example is a bit artificial, but I could not invent something simpler to illustrate the idea: you create "more semantic" type of exception and add some new information to the instance of some "more universal" exception type, in this case, "purpose", because "your code knows particular purpose better".

Are you getting the idea?

—SA
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900