C# > Advanced C# > Exception Handling > Using System.Exception
Custom Exception Class with Logging
This snippet demonstrates how to create a custom exception class that inherits from `System.Exception`. It includes properties for additional error information and uses logging for better diagnostics.
Code Snippet
This code defines a custom exception class, `CustomException`, which inherits from `System.Exception`. It includes an `ErrorCode` property to store a specific error identifier and a `Timestamp` property to record when the exception occurred. The constructor takes a message and error code, and it calls `LogException` to write the error to a file. The `Example` class demonstrates how to throw and catch the custom exception, along with a general exception handler. The logging mechanism is implemented to provide additional details about the error for debugging purposes.
using System;
using System.IO;
public class CustomException : Exception
{
public int ErrorCode { get; set; }
public DateTime Timestamp { get; set; }
public CustomException(string message, int errorCode) : base(message)
{
ErrorCode = errorCode;
Timestamp = DateTime.Now;
LogException(message, errorCode);
}
public CustomException(string message, int errorCode, Exception innerException) : base(message, innerException)
{
ErrorCode = errorCode;
Timestamp = DateTime.Now;
LogException(message, errorCode);
}
private void LogException(string message, int errorCode)
{
string logFilePath = "error.log";
try
{
using (StreamWriter writer = new StreamWriter(logFilePath, true))
{
writer.WriteLine($"[{Timestamp}] Error Code: {errorCode}, Message: {message}");
}
}
catch (Exception logException)
{
Console.WriteLine($"Failed to log exception: {logException.Message}");
}
}
}
public class Example
{
public static void Main(string[] args)
{
try
{
// Simulate an error condition
int numerator = 10;
int denominator = 0;
if (denominator == 0)
{
throw new CustomException("Division by zero attempted.", 1001);
}
int result = numerator / denominator;
Console.WriteLine($"Result: {result}");
}
catch (CustomException ex)
{
Console.WriteLine($"Custom Exception caught: {ex.Message}, Error Code: {ex.ErrorCode}");
}
catch (Exception ex)
{
Console.WriteLine($"General Exception caught: {ex.Message}");
}
}
}
Concepts Behind the Snippet
The primary concept is to extend the built-in `System.Exception` class to create more specific exception types that can carry additional information relevant to the application's domain. This allows for more granular error handling and easier debugging. By implementing logging within the exception class, we centralize the error reporting, making it simpler to track and resolve issues. The use of `try-catch` blocks demonstrates exception handling, where code that might throw an exception is wrapped in a `try` block, and the `catch` block handles the exception if it occurs.
Real-Life Use Case
Imagine a banking application where various operations, such as withdrawals or transfers, can fail due to insufficient funds, invalid account numbers, or network issues. Creating custom exceptions like `InsufficientFundsException`, `InvalidAccountException`, and `NetworkException` allows the application to handle these specific scenarios differently. Each exception can include relevant data, such as the account number or the amount involved, and logging this information helps in auditing and debugging.
Best Practices
Interview Tip
When discussing exception handling in interviews, highlight the importance of creating custom exceptions for domain-specific errors. Explain how this improves code readability, maintainability, and error handling. Be prepared to discuss the benefits of logging exceptions and the role of inner exceptions in preserving the call stack.
When to Use Them
Use custom exceptions when you need to represent specific error conditions in your application that the standard exception types do not adequately cover. This is particularly important in complex systems where detailed error information is crucial for debugging and maintaining the application.
Memory Footprint
Custom exceptions increase the memory footprint slightly due to the additional properties and the logging mechanism. However, this overhead is typically negligible compared to the benefits of improved error handling and debugging. Consider the frequency of exception throwing when evaluating memory impact.
Alternatives
Alternatives to custom exceptions include using standard exception types with custom error codes or using a more generic error reporting mechanism. However, these approaches often lack the specificity and clarity that custom exceptions provide. Another alternative is using Result objects to represent the outcome of an operation, avoiding exceptions for expected error scenarios.
Pros
Cons
FAQ
-
Why should I create custom exception classes?
Custom exception classes provide a way to represent specific error conditions in your application more clearly than generic exception types. They allow you to include additional information about the error and handle specific error scenarios differently. -
How do I log exceptions?
You can log exceptions to a file, database, or other logging system. The example code demonstrates logging exceptions to a file using `StreamWriter`. Consider using a logging library like NLog or Serilog for more advanced logging features. -
What is an inner exception?
An inner exception is the original exception that caused another exception to be thrown. It preserves the call stack and provides valuable information for debugging. When catching and re-throwing an exception, always include the original exception as the inner exception.