Check out a free preview of the full C# and .NET Basics course
The "Exception Handling" Lesson is part of the full, C# and .NET Basics course featured in this preview video. Here's what you'd learn in this lesson:
Spencer introduces exceptions as errors thrown by the runtime. He demonstrates how to handle exceptions using a try-catch block and explains the purpose of the try and catch sections. He also discusses the finally block, which always executes regardless of whether an exception is caught or not.
Transcript from the "Exception Handling" Lesson
[00:00:00]
>> Spencer Schneidenbach: Let's get to one of my favorite topics, exceptions. So this is a quote that I use all the time. A large fraction of the flaws in software development are due to programmers not fully understanding their states, all possible states their code may execute in. So exceptions are errors that are thrown by the runtime and they can be thrown for any number of reasons.
[00:00:17]
They can be thrown by your own code, they can be thrown by code written by Microsoft, they could be they could be thrown as part of the code inside of a framework. So exceptions are really an important part of development, especially in C Sharp, and understanding what they are and how to predict them and how to handle them is really important.
[00:00:38]
So the thing that we do to control them, we're gonna introduce a different control flow type, which is, I'm gonna delete this, close that, and I am going to write out what's called a try-catch.
>> Spencer Schneidenbach: So, let's break down what this statement is doing. So, the try-catch, the try is basically, I am executing code that I think may throw an exception.
[00:01:05]
The catch is where the code that will actually execute if an exception is caught. So let me demonstrate that. So I mentioned the DateTime.Parse method earlier. So if we give it just a random string. What's gonna happen? It's probably gonna throw an exception, right? And I can see that actually, if you go here, you can hover over it, it will tell you the kinds of exceptions that it will throw.
[00:01:33]
It will tell you if the argument is null, it will throw the argument null exception. So if you give it a null string. Or if you've given an invalid string, a format exception will be thrown. So we can see that here. I will console.writeline something went wrong. Boom, and then we will Ctrl + Shift + Tilde dotnet run.
[00:01:59]
And then we see that something went wrong. It's because at this point, we got an exception. And let me show you kinda what that looks like. I'm gonna run this with the debugger, which I haven't done yet. So I've put what's down, what's called a break point. And essentially, I wanna say that if this line is going to be executed, then I want you to stop there.
[00:02:18]
But it has to be run in debug mode, and debug mode has a performance penalty associated with it. It takes a lot of resources to run debug, comparatively speaking. So you can see that we've actually stopped at this point. We've hit the break point. We caught the exception and you can see that, if we hover over the exception, which is something that I do frequently, this is something that I love using my tooling for, right?
[00:02:40]
You can see that the type of exception that's thrown. You can get some more information about it. I really wanted to just do this to demonstrate that once an error hits here, it will fall down to here and and do what's called catch the exception. So now we could do something with it.
[00:02:57]
We can recover gracefully. We could ask the user to input something else, right? There's a lot of things we can do. It really depends on what we're looking for. Now, the base class, all exceptions are of this base class, which is system.exception, and there are no exceptions to that rule.
[00:03:16]
All things, all errors that are thrown are exception are of the exception class. They're of the exception type. But you can, if you want to, catch multiple types of exceptions, and you can also catch more derived types, as we call them. So let's say we wanted to catch the ArgumentNullException, right?
[00:03:35]
Because that's one of the two exceptions that gets handled here. So let's watch what happens when we do that. We have a breakpoint. We're running it in debug mode. And instead of going down here, we didn't have the exception be caught. So the CLR in our debugger rightfully told us, hey, at this line of code, this exception was thrown.
[00:03:55]
So what do you wanna do? So I'm just gonna keep going and it's just gonna crash the program. And that's because I've I've chosen to only catch an ArgumentNullException here at this line. But if I copy paste this, I can actually catch multiple kinds of exceptions. As you can see, the compiler tells me that I'm already catching this, so I don't need to do anything with it, or I can't do anything with it.
[00:04:18]
This code won't compile.
>> Spencer Schneidenbach: But I can catch this exception here now. And if I put my break point here and I put my break point here, I'll debug the project. And you can see that it skips over because the exception that's thrown is very clearly a FormatException, not an ArgumentNullException.
[00:04:42]
So, that is exception handling. So we'll see some more of that as we get into the course, yes?
>> Speaker 1: Do you typically log these exceptions in a file, or do you use a service?
>> Spencer Schneidenbach: That's a good question. It depends on the medium in which the program is executing.
[00:05:03]
So for example, in a cloud system, I'm almost certainly gonna be using logging into something like Application Insights or Datadog. Or some other program that allows me to see it like and I can log into a web interface and then get a readout of what happened to that exception with a lot of other telemetry.
[00:05:18]
If it's a console app that I wrote because once a day, we need to process a CSV file that came in from FTP. I'm probably just gonna log it to a file and then maybe send an email or something along those lines to say that there's an error or there was a problem processing this this record.
[00:05:37]
Good question.
>> Spencer Schneidenbach: One other, so we talked about catching multiple types of exceptions. There's one other part of the try-catch block that you should know, which is the finally block. So the finally block always executes no matter what. So as long as you've caught the error and you haven't rethread it, or sorry, even if you have to rethrown it.
[00:06:01]
Finally will always execute. So let's take a look at that. So we know that this method is gonna throw, so I'm gonna hit Play and we're gonna see something went wrong and then it printed finally because this will always run. The only time that doesn't run is if in the middle of handling an exception, the computer gets unplugged.
[00:06:22]
That's the only time. Let's see maybe a solar flare, too, I don't know. So a couple more notes. You can filter down even further, not just by type, but you can also say when an error message contains a specific line of or string, or maybe the exception has an additional property on it, maybe it has an error code.
[00:06:48]
An error code equals 1, 2, 3, 4, and you wanna handle that specific condition. You can do that. I do not write these a ton, but I do write them, especially when we're talking about, I'm catching an exception from a database operation that failed and it has this very specific message that it sends back.
[00:07:04]
So, useful to know, not necessarily, but for most cases, you're probably just gonna catch an exception without doing any other kind of wind condition. And then lastly, you are able to create your own exceptions this syntax will make a lot more sense after we talk about classes and you're able to throw your own exception.
[00:07:26]
So let's say for instance that I have a variable string name = Alice and I don't like Alice and actually if name doesn't equal Spencer, maybe there's some narcissism, I don't know. We'll throw an a new InvalidOperationException. So new is how you create a new instance of an exception.
[00:07:52]
We'll get into the new syntax when we get into classes. But the important thing that you need to know is that you are able to throw your own exceptions. And I don't think programmers do enough of this. The main reason that you would do that is if you had a method that you declared, something like public static void DoSomeProcessing, and you had some critical value here.
[00:08:20]
And that critical value needs to be a non-nullable string. So if you say, if string is null or whitespace critical value, you would throw a new ArgumentException. And give it a message that's helpful. That's typically when you would throw your own exceptions. Very useful, very, very important, very important part of the framework.
[00:08:50]
So I think that the bottom line for exceptions is that you should expect them. If I could credit a couple of things in my career, it's knowing SQL really well and knowing when exceptions are thrown and what states those things will happen. That has been a huge part of just making sure that if an exception is thrown, expecting it, and then being able to handle and self-recover from it.
[00:09:21]
When we get into null references, you saw that null reference exception earlier is probably the most common and frustrating exception for new dotnet developers and even dotnet developers in their career. Debugging them can be a pain, but they're important. So we'll get to that in a little bit, any questions?
[00:09:40]
>> Speaker 1: Why use finally if you could just write a statement after the try-catch?
>> Spencer Schneidenbach: So you might wanna use finally if you absolutely want this code to execute. And the reason you might do that is you may choose to rethrow the exception here. So there are reasons to do that.
[00:09:56]
You might catch this here and then log it to somewhere and then rethrow the exception so that way the processing for the client stops. Maybe there's some kind of business critical process we don't want to run because the system is in an invalid state, but we still have some code down here that we need to run.
[00:10:12]
That's when you would use the finally block as opposed to just writing it straight after. Really good question. By the way, the key word to rethrow an exception is throw. If you do this outside of the context of a catch statement, it's gonna error out and say you're not allowed to do this, because you're not throwing an exception.
[00:10:32]
By the way, this is a thing that you can do. You can rethrow the exception like this. Do not do that. Well, .NET will complain, it's a rethrow and caught exception changes stack information. So you really don't wanna throw ex like this. You'll lose precious debugging information. So always write your keyword as throw.
[00:10:52]
That is something that sometimes new developers get caught up on, but I don't see it most of the time. Just throw keyword by itself will rethrow the exception. So that way it does what we call, bubbling up to the caller. And we can see that here, if we we've run the project, you can see that we'll print the unhandled exception to here.
[00:11:11]
Yeah, perfect.
>> Speaker 2: Can you print x?
>> Spencer Schneidenbach: Yeah, absolutely.
>> Spencer Schneidenbach: Absolutely, so if you wanted to just print it or log it to someplace, you could do that here.
>> Spencer Schneidenbach: Awesome.
>> Spencer Schneidenbach: Cool, actually I'm sorry, yeah, that actually didn't rethrow there, let me try that again. We need to throw a ArgumentNullException, my bad, there we go.
[00:11:55]
Okay, yes you can absolutely write it to the console for sure.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops