Programming guide - Exceptions and Exception Handling 프로그래밍/C#2017. 8. 2. 14:44
- Exceptions and Exception Handling
- Using Exceptions
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/
Exceptions and Exception Handling
The C# language's exception handling features help you deal with any unexpected or exceptional situations that occur when a program is running. Exception handling uses the try
, catch
, and finally
keywords to try actions that may not succeed, to handle failures when you decide that it is reasonable to do so, and to clean up resources afterward. Exceptions can be generated by the common language runtime (CLR), by the .NET Framework or any third-party libraries, or by application code. Exceptions are created by using the throw
keyword.
In many cases, an exception may be thrown not by a method that your code has called directly, but by another method further down in the call stack. When this happens, the CLR will unwind the stack, looking for a method with a catch
block for the specific exception type, and it will execute the first such catch
block that if finds. If it finds no appropriate catch
block anywhere in the call stack, it will terminate the process and display a message to the user.
In this example, a method tests for division by zero and catches the error. Without the exception handling, this program would terminate with a DivideByZeroException was unhandled error.
class ExceptionTest
{
static double SafeDivision(double x, double y)
{
if (y == 0)
throw new System.DivideByZeroException();
return x / y;
}
static void Main()
{
// Input for test purposes. Change the values to see
// exception handling behavior.
double a = 98, b = 0;
double result = 0;
try
{
result = SafeDivision(a, b);
Console.WriteLine("{0} divided by {1} = {2}", a, b, result);
}
catch (DivideByZeroException e)
{
Console.WriteLine("Attempted divide by zero.");
}
}
}
Exceptions Overview
Exceptions have the following properties:
Exceptions are types that all ultimately derive from
System.Exception
.Use a
try
block around the statements that might throw exceptions.Once an exception occurs in the
try
block, the flow of control jumps to the first associated exception handler that is present anywhere in the call stack. In C#, thecatch
keyword is used to define an exception handler.If no exception handler for a given exception is present, the program stops executing with an error message.
Do not catch an exception unless you can handle it and leave the application in a known state. If you catch
System.Exception
, rethrow it using thethrow
keyword at the end of thecatch
block.If a
catch
block defines an exception variable, you can use it to obtain more information about the type of exception that occurred.Exceptions can be explicitly generated by a program by using the
throw
keyword.Exception objects contain detailed information about the error, such as the state of the call stack and a text description of the error.
Code in a
finally
block is executed even if an exception is thrown. Use afinally
block to release resources, for example to close any streams or files that were opened in thetry
block.Managed exceptions in the .NET Framework are implemented on top of the Win32 structured exception handling mechanism. For more information, see Structured Exception Handling (C/C++) and A Crash Course on the Depths of Win32 Structured Exception Handling.
Related Sections
See the following topics for more information about exceptions and exception handling:
C# Language Specification
For more information, see the C# Language Specification. The language specification is the definitive source for C# syntax and usage.
See Also
SystemException
C# Programming Guide
C# Keywords
throw
try-catch
try-finally
try-catch-finally
Exceptions
Exception Hierarchy
Writing Reliable .NET Code
Minidumps for Specific Exceptions
Using Exceptions
In C#, errors in the program at run time are propagated through the program by using a mechanism called exceptions. Exceptions are thrown by code that encounters an error and caught by code that can correct the error. Exceptions can be thrown by the .NET Framework common language runtime (CLR) or by code in a program. Once an exception is thrown, it propagates up the call stack until a catch
statement for the exception is found. Uncaught exceptions are handled by a generic exception handler provided by the system that displays a dialog box.
Exceptions are represented by classes derived from Exception. This class identifies the type of exception and contains properties that have details about the exception. Throwing an exception involves creating an instance of an exception-derived class, optionally configuring properties of the exception, and then throwing the object by using the throw
keyword. For example:
class CustomException : Exception
{
public CustomException(string message)
{
}
}
private static void TestThrow()
{
CustomException ex =
new CustomException("Custom exception in TestThrow()");
throw ex;
}
After an exception is thrown, the runtime checks the current statement to see whether it is within a try
block. If it is, any catch
blocks associated with the try
block are checked to see whether they can catch the exception. Catch
blocks typically specify exception types; if the type of the catch
block is the same type as the exception, or a base class of the exception, the catch
block can handle the method. For example:
static void TestCatch()
{
try
{
TestThrow();
}
catch (CustomException ex)
{
System.Console.WriteLine(ex.ToString());
}
}
If the statement that throws an exception is not within a try
block or if the try
block that encloses it has no matching catch
block, the runtime checks the calling method for a try
statement and catch
blocks. The runtime continues up the calling stack, searching for a compatible catch
block. After the catch
block is found and executed, control is passed to the next statement after that catch
block.
A try
statement can contain more than one catch
block. The first catch
statement that can handle the exception is executed; any following catch
statements, even if they are compatible, are ignored. Therefore, catch blocks should always be ordered from most specific (or most-derived) to least specific. For example:
static void TestCatch2()
{
System.IO.StreamWriter sw = null;
try
{
sw = new System.IO.StreamWriter(@"C:\test\test.txt");
sw.WriteLine("Hello");
}
catch (System.IO.FileNotFoundException ex)
{
// Put the more specific exception first.
System.Console.WriteLine(ex.ToString());
}
catch (System.IO.IOException ex)
{
// Put the less specific exception last.
System.Console.WriteLine(ex.ToString());
}
finally
{
sw.Close();
}
System.Console.WriteLine("Done");
}
Before the catch
block is executed, the runtime checks for finally
blocks. Finally
blocks enable the programmer to clean up any ambiguous state that could be left over from an aborted try
block, or to release any external resources (such as graphics handles, database connections or file streams) without waiting for the garbage collector in the runtime to finalize the objects. For example:
static void TestFinally()
{
System.IO.FileStream file = null;
//Change the path to something that works on your machine.
System.IO.FileInfo fileInfo = new System.IO.FileInfo(@"C:\file.txt");
try
{
file = fileInfo.OpenWrite();
file.WriteByte(0xF);
}
finally
{
// Closing the file allows you to reopen it immediately - otherwise IOException is thrown.
if (file != null)
{
file.Close();
}
}
try
{
file = fileInfo.OpenWrite();
System.Console.WriteLine("OpenWrite() succeeded");
}
catch (System.IO.IOException)
{
System.Console.WriteLine("OpenWrite() failed");
}
}
If WriteByte()
threw an exception, the code in the second try
block that tries to reopen the file would fail if file.Close()
is not called, and the file would remain locked. Because finally
blocks are executed even if an exception is thrown, the finally
block in the previous example allows for the file to be closed correctly and helps avoid an error.
If no compatible catch
block is found on the call stack after an exception is thrown, one of three things occurs:
If the exception is within a finalizer, the finalizer is aborted and the base finalizer, if any, is called.
If the call stack contains a static constructor, or a static field initializer, a TypeInitializationException is thrown, with the original exception assigned to the InnerException property of the new exception.
If the start of the thread is reached, the thread is terminated.
Exception Handling
A try block is used by C# programmers to partition code that might be affected by an exception. Associated catchblocks are used to handle any resulting exceptions. A finally block contains code that is run regardless of whether or not an exception is thrown in the try
block, such as releasing resources that are allocated in the try
block. A try
block requires one or more associated catch
blocks, or a finally
block, or both.
The following examples show a try-catch
statement, a try-finally
statement, and a try-catch-finally
statement.
try
{
// Code to try goes here.
}
catch (SomeSpecificException ex)
{
// Code to handle the exception goes here.
// Only catch exceptions that you know how to handle.
// Never catch base class System.Exception without
// rethrowing it at the end of the catch block.
}
try
{
// Code to try goes here.
}
finally
{
// Code to execute after the try block goes here.
}
try
{
// Code to try goes here.
}
catch (SomeSpecificException ex)
{
// Code to handle the exception goes here.
}
finally
{
// Code to execute after the try (and possibly catch) blocks
// goes here.
}
A try
block without a catch
or finally
block causes a compiler error.
Catch Blocks
A catch
block can specify the type of exception to catch. The type specification is called an exception filter. The exception type should be derived from Exception. In general, do not specify Exception as the exception filter unless either you know how to handle all exceptions that might be thrown in the try
block, or you have included a throw statement at the end of your catch
block.
Multiple catch
blocks with different exception filters can be chained together. The catch
blocks are evaluated from top to bottom in your code, but only one catch
block is executed for each exception that is thrown. The first catch
block that specifies the exact type or a base class of the thrown exception is executed. If no catch
block specifies a matching exception filter, a catch
block that does not have a filter is selected, if one is present in the statement. It is important to position catch
blocks with the most specific (that is, the most derived) exception types first.
You should catch exceptions when the following conditions are true:
You have a good understanding of why the exception might be thrown, and you can implement a specific recovery, such as prompting the user to enter a new file name when you catch a FileNotFoundException object.
You can create and throw a new, more specific exception.
C#int GetInt(int[] array, int index) { try { return array[index]; } catch(System.IndexOutOfRangeException e) { throw new System.ArgumentOutOfRangeException( "Parameter index is out of range.", e); } }
You want to partially handle an exception before passing it on for additional handling. In the following example, a
catch
block is used to add an entry to an error log before re-throwing the exception.C#try { // Try to access a resource. } catch (System.UnauthorizedAccessException e) { // Call a custom error logging procedure. LogError(e); // Re-throw the error. throw; }
Finally Blocks
A finally
block enables you to clean up actions that are performed in a try
block. If present, the finally
block executes last, after the try
block and any matched catch
block. A finally
block always runs, regardless of whether an exception is thrown or a catch
block matching the exception type is found.
The finally
block can be used to release resources such as file streams, database connections, and graphics handles without waiting for the garbage collector in the runtime to finalize the objects. See using Statement for more information.
In the following example, the finally
block is used to close a file that is opened in the try
block. Notice that the state of the file handle is checked before the file is closed. If the try
block cannot open the file, the file handle still has the value null
and the finally
block does not try to close it. Alternatively, if the file is opened successfully in the try
block, the finally
block closes the open file.
System.IO.FileStream file = null;
System.IO.FileInfo fileinfo = new System.IO.FileInfo("C:\\file.txt");
try
{
file = fileinfo.OpenWrite();
file.WriteByte(0xF);
}
finally
{
// Check for null because OpenWrite might have failed.
if (file != null)
{
file.Close();
}
}
'프로그래밍 > C#' 카테고리의 다른 글
Programming guide - Indexers (0) | 2017.10.06 |
---|---|
Dictionary<TKey,TValue> Class (0) | 2017.08.19 |
Programming guide - Events (0) | 2017.08.01 |
Programming guide - Enumeration Types (0) | 2017.08.01 |
ConfigurationManager Class (0) | 2017.07.05 |