Top Exception Handling Examples in Programming
Table of contents:-
Exception handling Example
Code for exception handling
Custom exceptions with bankApp example
Access modifiers in c# and it's scope.
Scenario: File Reading
We’ll create a program that attempts to read a file. The file may or may not exist, and we will demonstrate how the program behaves with and without exception handling.
Without Exception Handling
using System;
using System.IO;
class Program
{
static void Main()
{
string filePath = "example.txt";
// Attempt to read the file
string content = File.ReadAllText(filePath);
// Print the content to the console
Console.WriteLine("File content:");
Console.WriteLine(content);
}
}
Explanation:
If the file
example.txt
does not exist, this code will throw aFileNotFoundException
, causing the application to crash and terminate abruptly.The user will see an unhandled exception error, and there’s no way to gracefully handle or inform them about the issue.
With Exception Handling
using System;
using System.IO;
class Program
{
static void Main()
{
string filePath = "example.txt";
try
{
// Attempt to read the file
string content = File.ReadAllText(filePath);
// Print the content to the console
Console.WriteLine("File content:");
Console.WriteLine(content);
}
catch (FileNotFoundException ex)
{
// Handle the specific exception
Console.WriteLine("Error: The file was not found.");
Console.WriteLine($"Details: {ex.Message}");
}
catch (Exception ex)
{
// Handle any other exceptions
Console.WriteLine("An unexpected error occurred.");
Console.WriteLine($"Details: {ex.Message}");
}
finally
{
// Cleanup or final operations
Console.WriteLine("Execution completed.");
}
}
}
Explanation:
try
Block: Contains the code that may throw an exception.catch
Block: Catches specific exceptions (e.g.,FileNotFoundException
) and provides a meaningful error message to the user.catch (Exception ex)
Block: Handles any other unexpected exceptions, ensuring that the program does not crash unexpectedly.finally
Block: Executes regardless of whether an exception was thrown or not. It can be used for cleanup operations or to display final messages.
Comparison
Without Exception Handling:
The program will crash if the file is not found.
Users receive a generic error message from the runtime, which may be confusing.
With Exception Handling:
The program handles the error gracefully by catching exceptions.
Users receive informative messages, and the program continues to execute or ends cleanly with a message indicating completion.
Benefits of Exception Handling:
User-Friendly: Provides clear feedback and prevents abrupt application termination.
Resilient: Allows the application to handle errors gracefully and continue running or exit cleanly.
Debugging: Helps identify and log errors for further investigation.
By using exception handling, the code becomes more robust and user-friendly, ensuring a smoother experience even when unexpected issues arise.
code for real life example
using System;
// Custom Exception for Insufficient Funds
public class InsufficientFundsException : Exception
{
public InsufficientFundsException(string message) : base(message) { }
}
// Custom Exception for Invalid Amount
public class InvalidAmountException : Exception
{
public InvalidAmountException(string message) : base(message) { }
}
public class BankAccount
{
public decimal Balance { get; private set; }
public BankAccount(decimal initialBalance)
{
if (initialBalance < 0)
throw new InvalidAmountException("Initial balance cannot be negative.");
Balance = initialBalance;
}
public void Withdraw(decimal amount)
{
if (amount <= 0)
throw new InvalidAmountException("Withdrawal amount must be greater than zero.");
if (amount > Balance)
throw new InsufficientFundsException("Insufficient funds for this withdrawal.");
Balance -= amount;
Console.WriteLine($"Withdrawal successful. New balance: {Balance:C}");
}
public void DisplayBalance()
{
Console.WriteLine($"Current balance: {Balance:C}");
}
}
class Program
{
static void Main()
{
BankAccount account = null;
try
{
// Set initial balance to a valid amount for demonstration
decimal initialBalance = 1000.00m;
// Create BankAccount object
account = new BankAccount(initialBalance);
}
catch (InvalidAmountException ex)
{
Console.WriteLine("Error: " + ex.Message);
return; // Exit the application if initialization fails
}
bool running = true;
while (running)
{
Console.Clear();
Console.WriteLine("Bank Account Menu");
Console.WriteLine("1. Check Balance");
Console.WriteLine("2. Withdraw Funds");
Console.WriteLine("3. Exit");
Console.Write("Please choose an option: ");
string choice = Console.ReadLine();
switch (choice)
{
case "1":
// Check Balance
account?.DisplayBalance();
break;
case "2":
// Withdraw Funds
Console.Write("Enter the amount to withdraw: ");
if (decimal.TryParse(Console.ReadLine(), out decimal amount))
{
try
{
account?.Withdraw(amount);
}
catch (InvalidAmountException ex) when (ex.Message.Contains("zero"))
{
Console.WriteLine("Error: " + ex.Message);
}
catch (InsufficientFundsException ex) when (ex.Message.Contains("Insufficient"))
{
Console.WriteLine("Error: " + ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("An unexpected error occurred.");
Console.WriteLine($"Details: {ex.Message}");
}
finally
{
Console.WriteLine("Transaction processing completed.");
}
}
else
{
Console.WriteLine("Invalid amount entered.");
}
break;
case "3":
// Exit
running = false;
Console.WriteLine("Exiting the application. Have a great day!");
break;
default:
Console.WriteLine("Invalid choice. Please select a valid option.");
break;
}
Console.WriteLine("Press Enter to return to the menu...");
Console.ReadLine();
}
}
}
Difference between const and readonly:
Example: ReadOnly Property in a Class
In this example, we'll create a class Person
with a read-only property Name
:
using System;
public class Person
{
// Private field to store the name
private readonly string name;
// Constructor to initialize the name
public Person(string name)
{
this.name = name;
}
// ReadOnly property to access the name
public string Name
{
get { return name; }
}
}
public class Program
{
public static void Main()
{
// Create a new Person object
Person person = new Person("Alice");
// Access the read-only property
Console.WriteLine("Name: " + person.Name);
// The following line would produce a compile-time error because Name is read-only
// person.Name = "Bob"; // Uncommenting this line will cause a compilation error
}
}
Explanation
Private Field: We declare a private field
name
in thePerson
class to store the value of theName
property. This field is marked asreadonly
, which means it can only be assigned a value during its declaration or in the constructor of the class.Constructor: The constructor initializes the
name
field when a new instance ofPerson
is created.ReadOnly Property: The
Name
property provides a way to read the value ofname
but does not provide a way to modify it. Since there is noset
accessor, the property is effectively read-only from outside the class.Usage: In the
Main
method, we create a newPerson
object and access theName
property. Trying to modify theName
property would result in a compile-time error because the property does not have aset
accessor.
This approach ensures that the Name
property is immutable after the Person
object is created, which is useful for scenarios where you want to ensure that certain values cannot be changed once set.
Access specifiers in C# with explanation and examples:-
In C#, access specifiers (also known as access modifiers) control the visibility and accessibility of classes, methods, properties, and other members. They help manage the encapsulation and protect the internal state of objects.
Here’s an overview of the main access specifiers in C#, along with examples to illustrate their usage:
1. public
The public
access specifier makes members accessible from any other class or assembly. This is the least restrictive access level.
Example:
using System;
public class Car
{
// Public field
public string Make;
// Public method
public void Start()
{
Console.WriteLine("Car started.");
}
}
public class Program
{
public static void Main()
{
Car myCar = new Car();
myCar.Make = "Toyota"; // Accessing public field
myCar.Start(); // Calling public method
Console.WriteLine("Car make: " + myCar.Make);
}
}
In this example, both the Make
field and the Start
method are public
, so they can be accessed from anywhere.
2. private
The private
access specifier restricts access to the containing class only. Members marked as private
cannot be accessed from outside the class.
Example:
using System;
public class Car
{
// Private field
private string _model;
// Public method to set the model
public void SetModel(string model)
{
_model = model;
}
// Public method to display the model
public void DisplayModel()
{
Console.WriteLine("Car model: " + _model);
}
}
public class Program
{
public static void Main()
{
Car myCar = new Car();
myCar.SetModel("Corolla"); // Accessing through public method
myCar.DisplayModel();
// The following line would produce a compile-time error
// myCar._model = "Civic"; // Error: _model is private
}
}
In this example, the _model
field is private
, so it can only be accessed and modified within the Car
class. Outside the class, the field is not accessible directly.
3. protected
The protected
access specifier allows access to members from within the containing class and from derived classes. It cannot be accessed from non-derived classes.
Example:
using System;
public class Vehicle
{
// Protected field
protected string _engineType;
// Protected method
protected void ShowEngineType()
{
Console.WriteLine("Engine type: " + _engineType);
}
}
public class Car : Vehicle
{
public void SetEngineType(string engineType)
{
_engineType = engineType; // Accessing protected field
}
public void DisplayEngineType()
{
ShowEngineType(); // Calling protected method
}
}
public class Program
{
public static void Main()
{
Car myCar = new Car();
myCar.SetEngineType("V8");
myCar.DisplayEngineType();
// The following line would produce a compile-time error
// myCar._engineType = "V6"; // Error: _engineType is protected
}
}
Here, _engineType
and ShowEngineType()
are protected
, so they can be accessed within the Car
class which derives from Vehicle
, but not from other classes.
4. internal
The internal
access specifier makes members accessible only within the same assembly. It is often used to hide implementation details from other assemblies while still allowing access within the assembly.
Example:
using System;
internal class InternalClass
{
// Internal field
internal string Data;
// Internal method
internal void DisplayData()
{
Console.WriteLine("Data: " + Data);
}
}
public class Program
{
public static void Main()
{
InternalClass obj = new InternalClass();
obj.Data = "Some data"; // Accessing internal field
obj.DisplayData(); // Calling internal method
}
}
In this example, InternalClass
and its members are internal
, so they are only accessible within the same assembly.
5. protected internal
The protected internal
access specifier is a combination of protected
and internal
. It allows access from within the same assembly or from derived classes in other assemblies.
Example:
using System;
public class BaseClass
{
// Protected internal field
protected internal string Info;
// Protected internal method
protected internal void ShowInfo()
{
Console.WriteLine("Info: " + Info);
}
}
public class DerivedClass : BaseClass
{
public void SetInfo(string info)
{
Info = info; // Accessing protected internal field
}
public void DisplayInfo()
{
ShowInfo(); // Calling protected internal method
}
}
public class Program
{
public static void Main()
{
DerivedClass obj = new DerivedClass();
obj.SetInfo("Protected Internal Data");
obj.DisplayInfo();
}
}
In this example, Info
and ShowInfo()
are protected internal
, so they can be accessed within the same assembly and by derived classes in other assemblies.
6. private protected
(C# 7.2 and later)
The private protected
access specifier is more restrictive than protected internal
. It allows access only from within the same assembly and derived classes within the same assembly.
Example:
using System;
public class BaseClass
{
// Private protected field
private protected string Secret;
// Private protected method
private protected void RevealSecret()
{
Console.WriteLine("Secret: " + Secret);
}
}
public class DerivedClass : BaseClass
{
public void SetSecret(string secret)
{
Secret = secret; // Accessing private protected field
}
public void ShowSecret()
{
RevealSecret(); // Calling private protected method
}
}
public class Program
{
public static void Main()
{
DerivedClass obj = new DerivedClass();
obj.SetSecret("Very Private Data");
obj.ShowSecret();
}
}
Here, Secret
and RevealSecret()
are private protected
, so they are accessible only within the same assembly and by derived classes within the same assembly.
Summary
public
: Accessible from anywhere.private
: Accessible only within the containing class.protected
: Accessible within the containing class and derived classes.internal
: Accessible only within the same assembly.protected internal
: Accessible within the same assembly and by derived classes.private protected
: Accessible within the same assembly and by derived classes within the same assembly.
These access specifiers help in designing classes and their members with proper encapsulation and access control.
Subscribe to my newsletter
Read articles from Mahir barot directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by