-1

I am trying to understand try/catch/throw with your own exception..

This is my custom exception class:

[Serializable]
class CustomException : FormatException
{
    /// <summary>
    /// Just create the exception
    /// </summary>
    public CustomException()
       : base()
    { }

    /// <summary>
    /// Create the exception with description
    /// </summary>
    /// <param name="message">Exception description</param>
    public CustomException(String message)
        : base(message)
    { }

    /// <summary>
    /// Create the exception with description and inner cause
    /// </summary>
    /// <param name="message">Exception description</param>
    /// <param name="innerException">Exception inner cause</param>
    public CustomException(String message, Exception ex)
        : base(message, ex)
    {
        MessageBox.Show(message + ex.Message);
    }
}

This is where i use it:

public static int ParseInput(string inInt)
{
    try
    {
        int input = int.Parse(inInt);
        return input;
    }
    catch (FormatException e)
    {
        throw new CustomException("Only use numbers! ", e);
    }
}

Now when I run the program and but in a char the program crash it shows the MessageBox then the program stops.. and show the classic error window with this info: An unhandled exception of type 'Spelregistrering.CustomException' occurred in Spelregistrering.exe

I want the program to run after the exception like it always do with a original try/catch.. what have I not understood or missed?

EDIT: I know about the TryParse, this code I just for me to better understand custom exceptions! And your answers show that I clearly don't understand them just yet..

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Newbie1337
  • 199
  • 1
  • 12
  • 2
    You are not supposed to throw after a catch.! – Mark Lakata Sep 12 '15 at 16:21
  • for parsing `int`s you should use [`int.TryParse`](https://msdn.microsoft.com/en-us/library/system.int32.tryparse%28v=vs.110%29.aspx) instead. – Nasreddine Sep 12 '15 at 16:22
  • You throw the exception, but you never later catch it, so it bubbles up and when nothing catches it, the program crashes. This is by design. – Tim Sep 12 '15 at 16:23
  • 1
    err ... of course you can throw (or even `rethrow`) after a catch ... it's just that when you don't handle it anywhere your programm will crash .... also @newbie: don't use `MessageBox.Show` do debug your programs (indeed you shouldn't do sideeffects in your constructors) – Random Dev Sep 12 '15 at 16:23
  • 1
    @MarkLakata There are good reasons to throw a new exception during handling of another exception, usually by packaging up the first exception inside another with more information, a more specific error message, etc. – Lasse V. Karlsen Sep 12 '15 at 16:30
  • or just to `rethrow` after you logged the problem, tried to shutdown some of your used resources, ... – Random Dev Sep 12 '15 at 16:31
  • What did you try to do there anyway? Show the *MessageBox*? – Random Dev Sep 12 '15 at 16:40
  • @LasseV.Karlsen I know there are good reasons the throw after a catch. this is not one of them! The OP wants to know why his exception is not caught, and it is because he threw it after he caught it and then didn't bother to catch it agin. – Mark Lakata Sep 12 '15 at 19:06

4 Answers4

2

The exceptions are there not to display MessageBox but to tell that something is seriously wrong what you can't handle. It this case is makes no sense to throw a new Exception and it also make no sense to declare a custom one.

In your case you should do something like this:

try
{
    int input = int.Parse(inInt);
    return input;
}
catch (FormatException e)
{
     MessageBox.Show("Only use numbers! " + e.Message);
     //you may return something here to make your ParseInput compilable.
}

What happened in your code is, that there was an exception raised, which you caught and then you immediately thrown a new exception which wasn't caught anywhere and that led to the crash.

You should declare your own exceptions when there is some specific critical state which you can't handle in your code to let the user of your code know what happened - Basically instead of throwing an instance of Exception, which is too general, you can create your own exception, which would be more specific.

Throwing an exception is rather expensive operation because of the stack enrollment. In your case you can use int.TryParse to avoid exceptions at all.

int input;    
if (int.TryParse(inInt, out input))
{
    //do something with the input.
}
else
{
    MessageBox.Show("Only use numbers!");
}

Edit:

As suggested by Arthur the try-catch suggested in this post cannot be used in the ParseInput because of the program steps in the catch there will be nothing returned from the method. To solve that I suggest not to implement and call ParseInput method at all and use a snippet with int.TryParse posted in this reply.

Matyas
  • 1,122
  • 5
  • 23
  • 29
  • Exceptions are not for users – jmoreno Sep 12 '15 at 16:27
  • 1
    @jmoren: Yes, they are... for the users of a library for example - In this case the user is a programmer. :-) when one uses `int.parse` the one is a user... and the one will receive the exception if there is something wrong (like the format). – Matyas Sep 12 '15 at 16:31
  • Your `catch` will fail to compile because it doesn't return anything. – Arthur Rey Sep 12 '15 at 16:34
  • @Arthur it won't... It would when Newbie1337 puts in it the method, thanks for mentioning that, I'll fix my reply. – Matyas Sep 12 '15 at 16:37
  • @Matyas: the users of a library are better described as "callers", it's not the programmer that receives the exception – jmoreno Sep 12 '15 at 17:02
  • @Matyas: shouldn't ex.Message b e.Message? – Luk6e Apr 29 '16 at 17:50
0

To put in my two pennies worth, you could go this way

public static int ParseInput(string inInt)
{
    int input;
    if (!int.TryParse(inInt, out input)) MessageBox.Show("Only use numbers!");

    return input;
}

This will return the parsed value if parsed successfully, otherwise it will tell the user and return 0.

Arthur Rey
  • 2,990
  • 3
  • 19
  • 42
  • 1
    while this is a better version of the code it does not seem to answer the OPs real question ... sorry – Random Dev Sep 12 '15 at 16:41
  • I posted this version because there are already 2 other answers. Just wanted to give the OP another way of doing things, which is always valuable IMHO. But I get your point. – Arthur Rey Sep 12 '15 at 17:10
0

I have now changed the code to look like this:

public static int ParseInmatning(string inInt)
{
    try
    {
        int input = int.Parse(inInt);
        return input;
        throw new CustomException("Wrong format");
    }
    catch (FormatException e)
    {
        MessageBox.Show("Only use numbers! " + e.Message, "ERROR!");
        return -1;
    }
}

and the test exception class:

[Serializable]
class CustomException : FormatException
{
    /// <summary>
    /// Just create the exception
    /// </summary>
    public CustomException()
    : base() {
    }

    /// <summary>
    /// Create the exception with description
    /// </summary>
    /// <param name="message">Exception description</param>
    public CustomException(String message)
    : base(message) {
    }

    /// <summary>
    /// Create the exception with description and inner cause
    /// </summary>
    /// <param name="message">Exception description</param>
    /// <param name="innerException">Exception inner cause</param>
    public CustomException(String message, Exception ex)
    : base(message, ex) {
    }
}

Is this correct now? ghaa i cant understand this.. :( and nooo guide explain this at a good level!

Newbie1337
  • 199
  • 1
  • 12
  • what are you trying to do here? No this will not work - look closely: is there any way the `throw` will ever be called? (Look at the `return`) – Random Dev Sep 12 '15 at 19:38
  • you can think of `throw` as something similar as `return` - `return` will *leave* the current function one level up - `throw` will *leave* the function the context till the next matching `block` up the call stack - so it can be 0 levels (if you catch it right away) or one (if the calling block catches it) and so on - if nothing on the call stack catches it your program will normally exit with an error code (there are *exceptions* to this rule if you are dealing with async or if you register a global handler and some ex. will stop your program no matter what - StackOverflow for example ;) ) – Random Dev Sep 12 '15 at 19:41
  • Ok, thx for trying explaning it for me, but i think im to stupid to understand :(. I am going a course about C# and they want us to create a custom exception class and use it.. but they do not explain how to do it or why!!! And i have tried to do different things, and looking at guides online but they just throw and do not show a real life example.. i dont understand how to handle the throw statment.. :( well I gues i have to keep on google.. – Newbie1337 Sep 12 '15 at 19:51
0

Newbie1337's answer to his/hers own question is bringing a new information to this so I'll try to answer it according to the new information as best I can.

I recommend to read this article, which basically says, that one should use custom exceptions only if there is a good reason. Also here on SO is this post about why to use custom exceptions.

So first, we should find the reason for having a custom exception.

Imagine that we are creating some framework and we want the user to be able to catch all exceptions which may be thrown from it - so the exception have something to do with the functionality of the framework.

To do that we need to create a custom exception OurFrameworkException derived from Exception. (this exception should be probably abstract).

Not to be boring we can add an error code in it:

[Serializable]
public abstract OurFrameworkException : Exception
{
    public int ErrorCode { get; private set; }

    public OurFrameworkException(int errorCode)
    {
        ErrorCode = errorCode;
    }
}

Then while we are implementing our framework we will get to the situation where there is a need of a custom exception.

Consider the framework to be a tool for code verification (poorly designed probably if following is possible). To get it working we will assume for the sake of the discussion, that we must first feed the framework with some rules and then run the verification it self and for some reason we can't do that in constructor. For example the rules may be changed dynamically. When there are no rules and the verification is run, we should probably throw an InvalidOperationException saying that we must first input the rules. But the original request stated above was, that all of the exceptions which are related to the framework should have a common base class to distinguish that they are related to it. So we need to implement OurFrameworkInvalidOperationException derived from OurFrameworkException:

[Serializable]
public OurFrameworkInvalidOperationException : OurFrameworkException
{
    public OurFrameworkInvalidOperationException(string description)
        : base(1) //for example
    {
        // store the description
    }
}

Now for the sake of the discussion let's have this rather stupid implementation of our "framework".

public class OurFramework
{
    string rules;        

    public void SetRules(string rules)
    {
        this.rules = rules;
    }

    public bool IsValid(string input)
    {
        if (!string.IsNullOrEmpty(rules)
        {
            return input == rules; //valid state is when the input is the same as the rules
        }
        else
        {
            throw new OurFrameworkInvalidOperationException("specify rules first");
        }
    }
}

And this is how someone would use our "very intelligent" framework:

OurFramework framework = new OutFramework();
//some inicialization
//the user should call here: framework.SetRules("rule");
bool isValid = false;
try
{
    isValid = framework.Validate(input);
}
catch(OurFrameworkInvalidOperationException)
{
    //tell the user that the rules are not filled in in the GUI somewhere.
}
catch(OurFrameworkOtherException)
{
    //give the user a similar warning as previously about something else.
}
catch(OurFrameworkException)
{
    //a general unspecified framework error occurred in the framework.
}
catch(Exception) //everything else
{
    //something unrelated to the framework or unhandled in the framework occurred.
}

if (isValid)
{
    //do stuff.
}

In the end this, here is one of many articles about how the custom exceptions should be implemented.

Community
  • 1
  • 1
Matyas
  • 1,122
  • 5
  • 23
  • 29