0% found this document useful (0 votes)
7 views33 pages

UNIT 2 .NET

Object-oriented programming (OOP) in C# focuses on using real-world objects for software design, emphasizing principles like encapsulation, inheritance, polymorphism, and abstraction to enhance reusability, extensibility, simplicity, and maintainability. OOP promotes modularity and code organization, allowing developers to create components that encapsulate functionality and manage memory efficiently through automatic garbage collection. Key concepts include the structure of classes, event handling, and the use of modules for better code organization within .NET assemblies.

Uploaded by

Nitin Sharma
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views33 pages

UNIT 2 .NET

Object-oriented programming (OOP) in C# focuses on using real-world objects for software design, emphasizing principles like encapsulation, inheritance, polymorphism, and abstraction to enhance reusability, extensibility, simplicity, and maintainability. OOP promotes modularity and code organization, allowing developers to create components that encapsulate functionality and manage memory efficiently through automatic garbage collection. Key concepts include the structure of classes, event handling, and the use of modules for better code organization within .NET assemblies.

Uploaded by

Nitin Sharma
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 33

Object Oriented Programming (OOPs) in C#

Object-oriented programming (OOPs) in C# is a design approach where we think in terms of real-


world objects rather than functions or methods. Unlike procedural programming language, in OOPs,
programs are organized around objects and data rather than action and logic. Please have a look at
the following diagram to understand this better.

Reusability:

To address reusability, object-oriented programming provides something called Classes and Objects.
So, rather than copy-pasting the same code repeatedly in different places, you can create a class and
make an instance of the class, which is called an object, and reuse it whenever you want.

Extensibility:

Suppose you have a function and want to extend it with some new features that were impossible
with functional programming. You have to create an entirely new function and then change the
whole function to whatever you want. OOPs, this problem is addressed using concepts called
Inheritance, Aggregation, and Composition. In our upcoming article, we will discuss all these
concepts in detail.

Simplicity:

Because we don’t have extensibility and reusability in modular programming, we end up with lots of
functions and scattered code, and from anywhere we can access the functions, security is less. In
OOPs, this problem is addressed using Abstraction, Encapsulation, and Polymorphism concepts.

Maintainability:

As OOPs address Reusability, Extensibility, and Simplicity, we have good, maintainable, and clean
code, increasing the application’s maintainability.

What are the OOPs Principles or OOPs Concepts in C#?

OOPs provide 4 principles. They are


1. Encapsulation

2. Inheritance

3. Polymorphism

4. Abstraction

Note: Don’t consider Class and Objects as OOPs principle. We use classes and objects to implement
OOP Principles.

What are Abstraction and Encapsulation?

The process of representing the essential features without including the background details is
called Abstraction. In simple words, we can say that it is a process of defining a class by providing
necessary details to the external world, which are required by hiding or removing unnecessary
things.

The process of binding the data and functions together into a single unit (i.e., class) is
called Encapsulation. In simple words, we can say that it is a process of defining a class by hiding its
internal data members from outside the class and accessing those internal data members only
through publicly exposed methods or properties. Data encapsulation is also called data hiding
because, using this principle, we can hide the internal data from outside the class.

Abstraction and Encapsulation are related to each other. We can say that Abstraction is logical
thinking, whereas Encapsulation is its physical implementation.

Understanding Abstraction and Encapsulation with an Example:

Let us understand Abstraction and Encapsulation Principles with an example. Suppose you want to
design one class for providing the register functionality of a user. For that, what you need to do is
first you need to get the data and validate the data, then you need to get the connection string for
the database, and finally, you need to save the data in the database. And for this, you have three
methods, i.e., Validate, GetConnectionString, and SaveUser. If you provide access to these three
methods to the users of this class, then he may end up calling these methods in the wrong order, or
it may be possible that he may forget to call any of these methods.

So, here, you need to create one method called Register, and as part of that method, you need to call
all these methods (Validate, GetConnectionString, and SaveUser) in a proper sequence. Finally, you
need to give access to the Register method instead of the Validate, GetConnectionString, and
SaveUser methods. This is what we discussed is nothing but abstraction. How you implement this is
nothing but encapsulation. So, here, you need to create the Validate, GetConnectionString, and
SaveUser methods with a private access specifier so the user cannot access these methods. Make
the Register method Public so the user can access this method, as shown below.
We can achieve code Simplicity through Encapsulation and Abstraction.

What is Inheritance?

The process by which the members of one class are transferred to another class is called inheritance.
The class from which the members are transferred is called the Parent/Base/Superclass, and the class
that inherits the Parent/Base/Superclass members is called the Derived/Child/Subclass. We can
achieve code extensibility through inheritance.

What is Polymorphism?

Polymorphism is derived from the Greek word, where Poly means many and morph means faces/
behaviors. So, the word polymorphism means the ability to take more than one form. Technically, we
can say that the same function/operator will show different behaviors by taking different types of
values or with a different number of values, called Polymorphism. There are two types of
polymorphism.

1. Static polymorphism/compile-time polymorphism/Early binding

2. Dynamic polymorphism/Run time polymorphism/Late binding

Static polymorphism is achieved by function overloading and operator overloading, whereas


dynamic polymorphism is achieved by function overriding.

Why do we need Object-Oriented Programming (OOPs) in C#?

If you want to represent real-world objects in a programming language for automating the business
by achieving Reusability, Extensibility, Simplicity, and Maintainability, then you need the concept of
OOPs. OOPs provide some principles, and by using those principles, we can develop real-world
objects in a programming language by achieving Reusability, Extensibility, Simplicity, and
Maintainability.

All living and non-living things are considered objects. So real-world objects such as Persons,
Animals, Bikes, Computers, etc., can be developed in object-oriented programming languages by
using the OOPs concept.

Advantages of OOP in C#:

Here’s a summary of the key advantages and disadvantages of using OOP concepts in C#:

 Modularity: OOP promotes modular code by encapsulating data and behavior within classes.
This makes managing and maintaining large codebases easier since you can work on
individual classes independently.
 Code Reusability: Inheritance allows you to create new classes by reusing existing ones (base
classes). This reduces code duplication and promotes a “write once, use many times”
approach.

 Abstraction: OOP allows you to create abstract classes and interfaces that define a contract
without providing implementation details. Abstraction simplifies complex systems by hiding
unnecessary details.

 Polymorphism: Polymorphism enables you to write code that can work with objects of
different classes through a common interface or base class. This flexibility simplifies code and
allows for extensibility.

 Encapsulation: Encapsulation restricts access to the internal state of objects, promoting data
integrity and security. You can control access to fields and methods using access modifiers
like public, private, protected, and internal.

 Maintenance and Debugging: OOP’s modular and organized structure makes debugging and
maintaining code easier. Changes in one class typically have limited impact on other parts of
the code.

 Scalability: OOP principles can help create scalable and extensible software systems. New
features can often be added by creating new classes and extending existing ones without
modifying the existing code.

 Readability: OOP promotes code that is more human-readable and self-explanatory. Classes
and objects map closely to real-world entities and interactions, making it easier for
developers to understand the code’s purpose.

Points to Remember:

1. Object-oriented programming Principles or OOP Concepts in C# are design principles that


suggest how we should develop a program so that we can reuse it from other layers of the
project effectively and with high scalability.

2. Scalability means we have to develop the project in such a way that it should accept future
changes without making major changes to the project. Small changes also should be
accepted from external files like properties files, XML files, etc. Scalability is achieved by
developing classes by integrating them in a loosely coupled way.

3. We should develop the project with scalability as there will be business growth. Due to the
business growth, we must add required changes to the project with minimal modifications.

4. As a developer, we must remember that in the initial stage of business, the customer never
makes a significant investment. As the business grows, customers increase investment
according to the growing requirements added to the projects. To add those new
requirements, we should not design the project entirely.

5. So, we must strictly design the project by following OOP principles, even though they are not
needed at the initial stage, but for accepting future changes.

Object Lifetime

Object lifetime is the time when a block of memory is allocated to this object during some process of
execution and that block of memory is released when the process ends. Once the object is allocated
with memory, it is necessary to release that memory so that it is used for further processing,
otherwise, it would result in memory leaks. We have a class in .Net that releases memory
automatically for us when the object is no longer used. We will try to understand the entire scenario
thoroughly of how objects are created and allocated memory and then deallocated when the object
is out of scope.
The class is a blueprint that describes how an instance of this type will look and feel in memory. This
instance is the object of that class type. A block of memory is allocated when the new keyword is
used to instantiate the new object and the constructor is called. This block of memory is big enough
to hold the object. When we declare a class variable it is allocated on the stack and the time it hits a
new keyword and then it is allocated on the heap. In other words, when an object of a class is
created it is allocated on the heap with the C# new keyword operator. However, a new keyword
returns a reference to the object on the heap, not the actual object itself. This reference variable is
stored on the stack for further use in applications.

When the new operator is used to create an object, memory is taken from the managed heap for this
object and the managed heap is more than just a random chunk of memory accessed by the CLR.
When the object is no longer used then it is de-allocated from the memory so that this memory can
be reused.

The key pillar of the .NET Framework is the automatic garbage collection that manages memory for
all .NET applications. When an object is instantiated the garbage collector will destroy the object
when it is no longer needed. There is no explicit memory deallocation since the garbage collector
monitors unused objects and does a collection to free up memory that is an automatic process. The
Garbage Collector removes objects from the heap when they are unreachable by any part of your
codebase. The .Net garbage collector will compact empty blocks of memory for the purpose of
optimization.

The heap is categorized into three generations so it can handle long-lived and short-lived objects.
Garbage collection primarily occurs with the reclamation of short-lived objects that typically occupy
only a small part of the heap.

Generations

There are the following three generations of objects on the heap:

 Generation 0: Newly created objects are in Generation 0. These objects on Generation 0 are
collected frequently to ensure that short-lived objects are quickly collected and the memory
is released. Objects that survive Generation 0, the collections are promoted to Generation 1.
Most objects are reclaimed for garbage collection in Generation 0 and do not survive to the
next generation.

 Generation 1: Objects that are collected less frequently than Generation 0 and contains
longer-lived objects that were promoted from Generation 0. Objects that survive Generation
1, collection are promoted to Generation 2.

 Generation 2: Objects promoted from Generation 1 that are the longest-lived objects and
collected infrequently. The overall strategy of the garbage collector is to collect and move
longer-lived objects less frequently.

The garbage collector cleans up managed resources automatically since the managed code is directly
targeted by the CLR. But when the object uses unmanaged resources like database connections or
file manipulation, that needs to be released manually and this can be done by a finalize method.

We use the destructor method using the (~) sign in our code to destroy the objects and this
destructor is converted into a finalize method (check in the compiled code). This is known as a
finalization process. If we are implementing Finalize(), we do not have control since when this
method should be called the garbage collector takes care of this on its own. In the finalization
process, there are two collection cycles to completely release the object's memory. During the first
collection pass, the object is flagged for finalization. After the finalization occurs, the garbage
collector can reclaim the object's memory and the memory is released.
There is another method, Dispose(), that releases managed and unmanaged resources explicitly.
This method is the single method in an IDisposable interface and can be used to release unmanaged
resources manually.

What is a component in C#?

Components are an important building block of software. In terms of software architecture, there are
a lot of principles regarding components that should be adhered to (high cohesion, low coupling, no
cycles etc.).

In C#, a "component" essentially refers to a reusable building block of code, typically implemented as
a class, that encapsulates specific functionality within an application, often utilizing
the System.ComponentModel.Component base class to provide features like event handling and
lifecycle management; key aspects include:

Core Concepts:

 Class Structure:

A component is essentially a C# class with properties, methods, and events that define its behavior
and interactions with other parts of the application.

 Base Class:

The System.ComponentModel.Component class serves as the foundation for most C# components,


providing features like the Disposed event for managing resource cleanup.

 Events:

Components often raise events to signal changes in their state or to notify other parts of the
application about significant occurrences.

 Properties:

Properties define accessible attributes of a component, allowing for controlled data access and
modification.

 Methods:

Methods encapsulate the core functionality of a component, performing specific operations or


calculations.

Key Use Cases:

 UI Controls:

Many UI elements in a Windows Forms or WPF application are considered components, like buttons,
textboxes, and listboxes, as they provide visual elements with interactive functionality.

 Custom Components:

Developers can create custom components to encapsulate complex logic or functionality that can be
reused across different applications or parts of the same application.

 Web Services:

In ASP.NET, web services can be designed as components, allowing for modular development and
easy integration with other applications.

Example Component Structure:

using System.ComponentModel;
public class MyCustomComponent : Component

// Properties

public string Text { get; set; }

// Events

public event EventHandler TextChanged;

// Constructor

public MyCustomComponent()

// Initialization logic

// Methods

public void SetText(string newText)

Text = newText;

OnTextChanged(EventArgs.Empty); // Raise event when text changes

protected virtual void OnTextChanged(EventArgs e)

TextChanged?.Invoke(this, e);

Modules: In C#, a "module" refers to a collection of code within a .NET assembly, essentially a
compiled unit containing one or more namespaces and their associated types (classes, interfaces,
structs, enums) which can be used by other applications; essentially, a logical grouping of code within
a larger program, promoting modularity and code organization.

Key points about modules in C#:

 Assembly Structure:

A single assembly can contain multiple modules, each represented as a separate .dll or .exe file,
allowing for more granular code organization and deployment.

 Namespace Organization:

Namespaces within a module help categorize and prevent naming conflicts between different code
sections.

 Access Control:

Modules can utilize access modifiers (public, private, protected) to control visibility of types and
members within the module, defining what parts can be accessed by other modules.

 Reflection Usage:
The .NET Framework's reflection capabilities allow you to dynamically access information about
modules, types, and members at runtime, enabling flexible code execution.

How to create a module in C#:

 Project Setup:

Create a new C# project in your IDE, typically a class library project to generate a module as a DLL
file.

 Define Namespace:

Within your code file, use the namespace keyword to define the scope for your module's types.

 Create Types:

Declare classes, interfaces, structs, and enums within your namespace to represent the functionality
of your module.

Example Code:

Code

// "MathUtils.cs" file in a C# project


namespace MyMathLibrary
{
public class Calculator
{
public static int Add(int num1, int num2)
{
return num1 + num2;

public static double CalculateSquareRoot(double number)

return Math.Sqrt(number);

Important Considerations:

 Naming Conventions:

Follow standard naming conventions for modules and types within them to maintain code clarity.

 Versioning:

When creating modules that might be used by multiple applications, carefully manage versioning to
avoid compatibility issues.

 Dependency Management:

Consider using a package manager (like NuGet) to efficiently manage dependencies between your
modules and external libraries.

Cloneable object
In C#, a cloneable object is an object that implements the ICloneable interface, allowing you to
create a copy (or clone) of the object, essentially creating a new, independent instance with the
same data as the original, enabling you to modify the copy without affecting the original object; this
is achieved through the Clone() method defined within the interface.

Key points about cloneable objects in C#:

 ICloneable Interface:

 This is a simple interface with a single method called Clone() which returns an object
of the same type as the original.

 The Clone() method is responsible for creating a copy of the object, but it does not
specify whether the copy is a "shallow" or "deep" copy.

 Shallow Copy vs Deep Copy:

 Shallow Copy: When you perform a shallow copy, only the top-level properties of an
object are copied. If the object contains references to other objects, the copies of
those references are also copied, meaning changes to the referenced objects in the
clone will affect the original object.

 Deep Copy: A deep copy creates a completely independent copy of the object,
including copies of any nested objects referenced by the original object.

How to implement cloneable objects:

1. Implement ICloneable: Make your class implement the ICloneable interface.

2. Override Clone() method:

o Within your class, override the Clone() method to create a new instance of your
object and copy all relevant data from the current object to the new instance.

o For a shallow copy, you can often use the protected MemberwiseClone() method
from the System.Object class.

o For a deep copy, you need to manually iterate through all properties and recursively
clone any nested objects.

Example:

Code

public class Person : ICloneable


{
public string Name { get; set;

}
public int Age { get; set; }

public object Clone()

{
Person clone = (Person)MemberwiseClone(); // Shallow copy
return clone;
}

}
// Usage

Person originalPerson = new Person { Name = "John", Age = 30 };


Person clonedPerson = (Person)originalPerson.Clone();
clonedPerson.Age = 31; // Modifying the clone does not affect the original

Important Considerations:

 When to use cloning:

Cloning is useful when you need to create a separate, modifiable copy of an object without changing
the original state.

 Deep copy complexity:

Implementing a deep copy can become complex when dealing with complex object graphs with
nested objects.

 Alternative approaches:

Depending on your situation, you might consider using serialization/deserialization or dedicated


cloning libraries to manage deep copying more easily.

C# | Clone() Method

In C#, Clone() is a String method. It is used to clone the string object, which returns another copy of
that data.
In other words, it returns a reference to this instance of String. The return value will be only another
view of the same data. Clone method called directly on current String instance. This method will not
take any parameters.

Syntax:

public object Clone()

Return Value Type: System.Object or we can say this instance of String.

Below program illustrate the use of Clone() Method:

// C# program to illustrate

// Clone() method

using System;

class CLN {

// Main Method

public static void Main(string[] args)

string s1 = "Hello World";

// Cannot implicitly convert

// type object to the string.


// So explicit conversion

// using Clone() method

string s2 = (String)s1.Clone();

// Displaying both the string

Console.WriteLine("String : {0}", s1);

Console.WriteLine("Clone String : {0}", s2);

C# | Clone() Method

In C#, Clone() is a String method. It is used to clone the string object, which returns another copy of that data.

In other words, it returns a reference to this instance of String. The return value will be only another view of the
same data. Clone method called directly on current String instance. This method will not take any parameters.

Syntax:

public object Clone()

Return Value Type: System.Object or we can say this instance of String.

Below program illustrate the use of Clone() Method:

// C# program to illustrate

// Clone() method

using System;

class Cln {

// Main Method

public static void Main(string[] args)

string s1 = "Hello World";

// Cannot implicitly convert

// type object to the string.

// So explicit conversion

// using Clone() method

string s2 = (String)s1.Clone();

// Displaying both the string


Console.WriteLine("String : {0}", s1);

Console.WriteLine("Clone String : {0}", s2);

Output:

String : Hello World

Clone String : Hello World

Output:

String : Hello World

Clone String : Hello World

C# Namespace

Namespaces play an important role in managing related classes in C#. The .NET Framework uses
namespaces to organize its built-in classes. For example, there are some built-in namespaces in .NET
such as System, System.Linq, System.Web, etc. Each namespace contains related classes.

A namespace is a container for classes and namespaces. The namespace also gives unique names to
its classes thereby you can have the same class name in different namespaces.

In C#, a namespace can be defined using the namespace keyword.

namespace School

// define classes here

Classes under the same namespace can be referred to as namespace.classname syntax. For example,
the Student class can be accessed as School.Student.

namespace CSharpTutorials

class Program

static void Main(string[] args)

School.Student std = new School.Student();

School.Course cs = new School.Course();

}
}

To use classes under a namespace without the fully qualified name, import the namespace with
the using keyword at the top of C# class file.

using System; //built-in namespace

using School;

namespace CSharpTutorials

class Program

static void Main(string[] args)

Student std = new Student();

C# Indexers

In C#, an indexer allows an instance of a class or struct to be indexed as an array. When an indexer is
defined for a class, then that class will behave like a virtual array. Array access operator i.e. ([ ]) is
used to access the instance of the class which uses an indexer. A user can retrieve or set the indexed
value without pointing to an instance or a type member. The main difference between Indexers
and Properties is that the accessors of the indexers (get and set) take parameters, whereas
properties do not.

Syntax:

[Access_modifier] [Return_type] this [Parameter_list]


{
get

{ // get block code }

set

{ // set block code }


}

In the above syntax,

 Access_Modifier: Specifies accessibility (e.g., public, private, protected, or internal).

 Return_Type: Specifies the data type of the value the indexer will return.

 this: Keyword that refers to the current instance of the class.

 Parameter_List: Specifies the parameters used to index the class.

 get and set: Accessors used to retrieve and assign values.


Example: This example demonstrates how to implement a simple indexer in a class.

// Use of Indexers in C#

using System;

class BCA

private string[] values = new string[3];

// Indexer declaration

public string this[int index]

// Getter

get

return values[index];

// Setter

set

values[index] = value;

class Program

static void Main()

Exp o = new Exp();

// Assign values using the indexer

o[0] = "C";

o[1] = "C++";

o[2] = "C#";
// Access values using the indexer

Console.WriteLine("First value: " + o[0]);

Console.WriteLine("Second value: " + o[1]);

Console.WriteLine("Third value: " + o[2]);

Output

First value: C

Second value: C++

Third value: C#

Explanation: In the above example, the class BCA uses an indexer to store and retrieve string values.
Values are assigned and accessed using array-like syntax (o[0], o[1], etc.).

Implementing Indexers

 Multiple-Index Parameters: Indexers can use multiple parameters for complex indexing,
enabling access to elements based on various criteria.

 Indexer Overloading: Indexers can be overload like methods allows multiple indexers with
varying parameter types or counts to access elements in a class or struct.

 Read-Only Indexers: Omitting the set accessor in an indexer makes it read-only, enabling
value retrieval while preventing modifications.

 Implicit vs. Explicit Interface: Indexers can be implemented implicitly or explicitly when
defined as part of an interface. Implicit implementation is used when the indexer is defined
within the class itself, while explicit implementation is used when the indexer is
implemented explicitly to resolve any naming conflicts.

 Indexers in Collections: Indexers are commonly used in collection classes, such


as dictionaries, lists, and arrays.Can access and manipulate elements within these collections
based on an index or key.

 Custom Classes: Indexers can be implemented in custom classes to provide customized


access to class members based on an index. Allows for more intuitive and expressive
interaction with instances of the class.

Example: This example shows an indexer with multiple parameters to perform different operations.

// C# Multi-Parameter Indexer

using System;

public class Indexer

private int[] data = new int[10];

// Indexer with multiple parameters


public int this[int index, bool square]

get

if (square)

return data[index] * data[index];

else

return data[index];

set

if (square)

data[index] = (int)Math.Sqrt(value);

else

data[index] = value;

// Overloaded indexer with string parameter

public int this[string n]

get

switch (n.ToLower())

case "first":

return data[0];

case "last":

return data[data.Length - 1];

default:

throw new

ArgumentException("Invalid index parameter.");

}
// Read-only indexer

public int this[int index]

get { return data[index]; }

public class BCA

public static void Main()

Indexer i = new Indexer();

// Setting values using multiple parameter indexer

i[0, false] = 5;

i[1, false] = 10;

i[2, false] = 15;

i[3, false] = 20;

// Getting values using multiple parameter indexer

Console.WriteLine(i[0, false]);

Console.WriteLine(i[1, true]);

// Getting values using string parameter indexer

Console.WriteLine(i["first"]);

Console.WriteLine(i["last"]);

// Getting values using read-only indexer

Console.WriteLine(i[2]);

Output

5
100

15

Explanation: In the above example we creat a indexer which can perform different operations and
can take multiple type parameters.

Key Points:

 There are two types of Indexers i.e.

o One Dimensional Indexer

o MultiDimensional Indexer

 This enables the object to be indexed in a similar way to arrays.

 A set accessor will always assign the value while the get accessor will return the value.

 “this” keyword is always used to declare an indexer.

 To define the value being assigned by the set indexer, ” value” keyword is used.

 Indexers are also known as the Smart Arrays or Parameterized Property in C#.

 Indexer can’t be a static member as it is an instance member of the class.

Method Overloading in C#
What is Method Overloading or Function Overloading in C#?
Method Overloading means it is an approach to defining multiple methods under the class with a
single name. So, we can define more than one method with the same name in a class. But the
point that you need to remember the parameters of all those methods should be different
(different in terms of number, type, and order of the parameters).
So, if we are defining multiple methods with the same name but with a different signature in a
class or in the Parent and Child Classes, then it is called Method Overloading in C#. That means
C#.NET not only allows method overloading in the same class but also allows method
overloading in Parent and Child classes. So, we can create a method in the Derived/Child class
with the same name as the method name defined in the Base/Parent class in C#.
In simple words, we can say that the Method Overloading in C# allows a class to have multiple
methods with the same name but with a different signature. The functions or methods can be
overloaded based on the number, type (int, float, etc), order, and kind (Value, Ref or Out) of
parameters. For a better understanding, please have a look at the below image. All the Methods
are going to be valid and based on the method call, the compiler will automatically decide which
overloaded version to be invoked.
As you can see in the above image, all the methods are having the same name i.e. Method but with
different parameters. If you look at the first two methods the number of parameters is different. The
first method takes zero parameters while the second method takes one parameter. Then if you
compare the second method with the third method, both are taking the same number of parameters
but of different types. The second method takes an integer parameter while the Third method takes
a string parameter. Further, if you compare the fourth and fifth method, both are having the same
number of parameter but the order of the parameters are different. The fourth method takes the
first parameter as an integer and the second parameter as a string while the Fifth method takes the
first parameter as a string and the second parameter as an integer. So, every method is different in
terms of number, type, and order of parameters, and this is called method overloading in C#.

The signature of a method consists of the name of the method and the data type, number, order, and
kind (Value, Ref or Out) of parameters. The point that you need to keep in mind is that the signature
of a method does not include the return type and the params modifiers. So it is not possible to
overload a method just based on the return type and params modifier. We will discuss Params
modifier in our upcoming article.

Example to Understand Method Overloading in C#:

using System;

namespace MethodOverloading

class Program

static void Main(string[] args)

Program obj = new Program();

obj.Method(); //Invoke the 1st Method

obj.Method(10); //Invoke the 2nd Method

obj.Method("Hello"); //Invoke the 3rd Method

obj.Method(10, "Hello"); //Invoke the 4th Method

obj.Method("Hello", 10); //Invoke the 5th Method

Console.ReadKey();

public void Method()

Console.WriteLine("1st Method");

public void Method(int i)

{
Console.WriteLine("2nd Method");

public void Method(string s)

Console.WriteLine("3rd Method");

public void Method(int i, string s)

Console.WriteLine("4th Method");

public void Method(string s, int i)

Console.WriteLine("5th Method");

Output:

Why Return Type is not considered as part of Method Overloading in C#?

Let us understand why return type is not considered as part of method overloading with an example.
Please have a look at the following image. Here, I have written two methods with the same name but
one method’s return type is void, and the other method’s return type is a string. See, as soon as we
create the second method, the compiler itself gives the compile time error saying Type ‘Program’
already defines a member called ‘Method’ with the same parameter types.

So, at the time of defining the method, only the compiler gave us an error. Now, still, you may have
doubt, return types are different, then why it is going to be invalid. To understand, let us try to invoke
the Method as shown in the below image. So, when we invoke the method, can you tell me which
version of the Method is going to be invoked? Because we have two methods that do not take any
parameter. So, here we will get the ambiguity problem and see the compiler also giving the same
ambiguity error The call is ambiguous between the following methods or properties:
‘Program.Method()’ and ‘Program.Method()’ while invoking the method.

When should we Overload Methods in C#?

The concept of Method Overloading falls under the Polymorphisms OOPs principle. Object Oriented
Programming is based on four principles i.e. Encapsulation, Abstraction, Inheritance, and
Polymorphism.

What is Polymorphism? Polymorphism is a mechanism of changing the behavior based on the inputs.
That means when the input changes, automatically the output or behavior changes. The best
example of polymorphism is ourselves. For example, when we hear something interesting or
something which is good for us, we feel happy. And when we hear something which is not good for
us, we feel sad. Suppose, you asked your father to purchase a bike, and if your father purchases a
bike for you then you will feel happy. And if your father says that I am not going to purchase a bike
for you, then you will feel sad. So, you are the same person, when you received something good, you
feel happy and when you receive something which is not good, you feel sad. This is called
polymorphism. Behaving in different ways based on the input received i.e. whenever the input
changes the output automatically changes.

Here, the input changes mean don’t think that the values changes. Input changes mean when we
change the number, type, and order of input the values are going to be changed. Don’t think that, if I
pass 10, I will get a value, if I pass 20, I will get a different value. For this, if else condition is sufficient,
overloading is not required. When you expect the output to be changed based on the number, type,
and order of inputs, then only you need to go for Method overloading in C#.

For a better understanding, please have a look at the following example. Here, we have created three
methods with the same name to perform the addition of two integers, two floats, and two strings.
So, when we give two integer numbers we will get one output and when we provide two string
values, then we will get a different output, and similarly, when we give two float numbers we will get
another output. That means when the input changes the output or behavior also automatically
changes. This is called polymorphism in C#.

using System;

namespace MethodOverloading

class Program

public void Add(int a, int b)


{

Console.WriteLine(a + b);

public void Add(float x, float y)

Console.WriteLine(x + y);

public void Add(string s1, string s2)

Console.WriteLine(s1 +" "+ s2);

static void Main(string[] args)

Program obj = new Program();

obj.Add(10, 20);

obj.Add(10.5f, 20.5f);

obj.Add("Pranaya", "Rout");

Console.ReadKey();

Output:

Suppose you are the user of the Program class and when you create the Program class instance and
when you type the object name and dot operator, then you will not see three different Add methods,
rather you will see only one Add method with two overloaded versions of the Add method as shown
in the below image.
Example to Understand Constructor Method Overloading in C#

Please have a look at the following example. Here, we are creating three different versions of the
Constructor, and each constructor takes a different number of parameters, and this is called
Constructor Overloading in C#.

using System;

namespace ConstructorOverloading

class ConstructorOverloading

int x, y, z;

public ConstructorOverloading(int x)

Console.WriteLine("Constructor1 Called");

this.x = 10;

public ConstructorOverloading(int x, int y)

Console.WriteLine("Constructor2 Called");

this.x = x;

this.y = y;

public ConstructorOverloading(int x, int y, int z)

Console.WriteLine("Constructor3 Called");

this.x = x;

this.y = y;
this.z = z;

public void Display()

Console.WriteLine($"X={x}, Y={y}, Z={z}");

class Test

static void Main(string[] args)

ConstructorOverloading obj1 = new ConstructorOverloading(10);

obj1.Display();

ConstructorOverloading obj2 = new ConstructorOverloading(10, 20);

obj2.Display();

ConstructorOverloading obj3 = new ConstructorOverloading(10, 20, 30);

obj3.Display();

Console.ReadKey();

Exception Handling in C#

Types of Errors in C#

When we write and execute our code in the .NET framework, two types of error occurrences are
possible. They are as follows:

1. Compilation Errors

2. Runtime Errors

Compilation Error in C#

The error that occurs in a program during compilation is known as a compilation error (compile-time
error). These errors occur due to syntactical mistakes in the program. These errors occur by typing
the wrong syntax, like missing double quotes in a string value and missing terminators in a
statement, typing wrong spelling for keywords, assigning wrong data to a variable, trying to create an
object for abstract class and interface, etc. So, whenever we compile the program, the compiler
recognizes these errors and shows us the list of errors.

In simple words, this type of error occurs due to a poor understanding of the programming language.
The compiler identifies these errors, which can be rectified before the program is executed. Thus,
these errors do not harm the program’s execution.

Runtime Error in C#

The errors that occur at the time of program execution are called runtime errors. These errors occur
at runtime due to various reasons, such as when we are entering the wrong data into a variable,
trying to open a file for which there is no permission, trying to connect to the database with the
wrong user ID and password, the wrong implementation of logic, and missing required resources,
etc. So, in simple words, we can say that the errors that come while running the program are called
runtime errors.

Runtime errors are dangerous because whenever they occur in the program, the program terminates
abnormally on the same line where the error occurred without executing the next line of code.

Note: The compiler will never check the logic; it will only check the syntaxes. So, the compiler will
identify the syntax error but not the logical error.

Are Runtime Errors Dangerous?

Yes, runtime errors are dangerous. If you are transferring money, there are two updated statements.
One update statement will deduct the money from the source account, and another update
statement will add the money to the destination account. Suppose the first update statement was
executed successfully, and before executing the second update statement, some runtime error
occurred. That means the money is deducted from your account but not added to the destination
account.

Then what will you do? You might be contacted by the bank, or you might go to the nearest bank and
investigate what happens. Why is the money deducted from my account, and why is it not added to
the destination account? This is the problem, and it is very dangerous, and it is because we are not
handling the runtime errors in our application.

What is an Exception in C#?

An Exception is a class in C# that is responsible for abnormal program termination when runtime
errors occur while running the program. These errors (runtime) are very dangerous because
whenever they occur, the program terminates abnormally on the same line where the error occurs
without executing the next line of code.

Note: Most people say Runtime Errors are Exceptions, which is not true. Exceptions are classes that
are responsible for the abnormal termination of the program when runtime errors occur.

Who is Responsible for the Abnormal Termination of the Program whenever Runtime Errors occur?

Objects of Exception classes are responsible for abnormal termination of the program whenever
runtime errors occur. These exception classes are predefined under BCL (Base Class Libraries), where
a separate class is provided for every different type of exception, like

1. IndexOutOfRangeException

2. FormatException

3. NullReferenceException

4. DivideByZeroException

5. FileNotFoundException

6. SQLException,

7. OverFlowException, etc.

Each exception class provides a specific exception error message. All the above exception classes are
responsible for abnormal program termination and will display an error message that specifies the
reason for abnormal termination, i.e., they provide an error message specific to that error.

So, whenever a runtime error occurs in a program, first, the Exception Manager under the CLR
(Common Language Runtime) identifies the type of error that occurs in the program. Then, the
Exception Manager creates an object of the Exception class related to that error and throws that
object, which will immediately terminate the program abnormally on the line where the error
occurred and display the error message related to that class.

Note: Exception class is the superclass of all Exception classes in C#.

What happens if an Exception is Raised in the Program in C#?

When an Exception is raised in C#, the program execution is terminated abnormally. That means the
statements placed after the exception-causing statements are not executed, but the statements
placed before that exception-causing statement are executed by CLR.

What does CLR do when an Exception Occurs in the program?

The CLR creates the exception class object that is associated with that logical mistake (exception) and
terminates the program execution by throwing that exception object by using the throw keyword. So,
we can say an exception is an event that occurs during the execution of a program that disrupts the
normal flow of instruction execution. Let’s understand this with an example.

Program Execution without Exception in C#

The following C# example shows program execution without exception. This is a very simple
program; we divide the numbers by two and print the result on the console.

using System;

namespace ExceptionHandlingDemo

class Program

static void Main(string[] args)

int a = 20;

int b = 10;

int c;

Console.WriteLine("A VALUE = " + a);

Console.WriteLine("B VALUE = " + b);

c = a / b;

Console.WriteLine("C VALUE = " + c);

Console.ReadKey();

Program Execution with Exception in C#

The following example shows program execution with an exception. As you can see in the code
below, we are dividing an integer number by 0, which is impossible in mathematics. So, it will throw
the Divide By Zero Exception in this case. The statements present before the exception-causing
statement, i.e., before c = a / b, are executed, and the statements present after the exception-
causing statement will not be executed.
using System;

namespace ExceptionHandlingDemo

class Program

static void Main(string[] args)

int a = 20;

int b = 0;

int c;

Console.WriteLine("A VALUE = " + a);

Console.WriteLine("B VALUE = " + b);

c = a / b;

Console.WriteLine("C VALUE = " + c);

Console.ReadKey();

Explanation:

The CLR terminates the program execution by throwing DivideByZeroException because the logical
mistake we committed here is dividing an integer number by integer zero. As we know, dividing an
integer number by zero is impossible. So, what CLR will do in this case, first it will check what type of
logical error is this. It will find that it will be a Divide By Zero Logical Error. So, then what CLR will do is
it will create an instance of the DivideByZeroException class, and then it will throw that instance by
using the throw statement like throw new DivideByZeroException(); From the above program, we
can define the exception technically as follows:

1. An exception is an event because when an exception is raised, the CLR internally executes
some logic to prepare exception-related messages.

2. Exceptions are signals because, by looking into the exception message, developers will take
necessary actions against that exception.

Is the above Exception Message User Understandable?

The answer is no. The user cannot understand the above exception message because it is a NET-
based exception message. So, the user cannot make any decision alone to resolve the above
problem. A developer should guide the user to solve the above problem.

What is the Solution to the Above problem?

The developer’s responsible for converting .NET exception messages into user-understandable
message formats. To solve this problem, the developer should handle the exception. Using the
exception handling mechanism, the developer can catch the exception and print and display user-
understandable messages.
What is Exception Handling in C#?

The process of catching the exception for converting the CLR-given exception message to an
understandable end-user message and stopping the abnormal termination of the program whenever
runtime errors occur is called Exception Handling in C#. Once we handle an exception under a
program, we will get the following advantages:

1. We can stop the Abnormal Termination

2. We can perform any corrective action that may resolve the problem.

3. Displaying a user-friendly error message so that the user can resolve the problem provided if
it is under his control.

Why do we need Exception Handling in C#?

We need exception handling in C# for two reasons.

1. To stop the Abnormal Termination of the program

2. To provide users with understandable messages when an exception is raised. So that users
can make their own decisions without the developer’s help.

Basically, by implementing Exception handling, we are giving a program the ability to talk to the user
on behalf of a developer.

What is the Procedure to Handle Exceptions in C#?

The Exception Handling in C# is a four steps procedure

1. Preparing the exception object that is appropriate to the current logical mistake.

2. Throwing that exception to the appropriate exception handler.

3. Catching that exception

4. Taking necessary actions against that exception

How can we handle an Exception in .NET?

There are two methods to handle the exception in .NET

1. Logical Implementation

2. Try Catch Implementation

What is the Logical Implementation in C# to Handle Exception?

In a logical implementation, we need to handle exceptions using logical statements. In real-time


programming, the first and foremost importance is always given to logical implementation only. If it
is impossible to handle an exception using logical implementation, then we need to go for try-catch
implementation.

Handling Exceptions in C# using Logical Implementation

The following example shows how to handle exceptions in C# using logical Implementation. Here, we
are checking the second number, i.e., the variable Number2 value. If it equals 0, then we are printing
one message saying the second number should not be zero. Otherwise, if the second number is not
zero, then we are performing our division operation and showing the results on the console. Here,
we are using an IF-ELSE logical statement to handle the exception.

using System;

namespace ExceptionHandlingDemo
{

class Program

static void Main(string[] args)

int Number1, Number2, Result;

Console.WriteLine("Enter First Number:");

Number1 = int.Parse(Console.ReadLine());

Console.WriteLine("Enter Second Number:");

Number2 = int.Parse(Console.ReadLine());

if (Number2 == 0)

Console.WriteLine("Second Number Should Not Be Zero");

else

Result = Number1 / Number2;

Console.WriteLine($"Result = {Result}");

Console.ReadKey();

Exception handling in C# using Try Catch implementation

The .NET framework provides three keywords to implement the try-catch implementation. They are
as follows:

1. Try

2. Catch

3. finally

Try Block:

The try keyword establishes a block in which we need to write the exception causing and its related
statements. That means exception-causing statements and the related statements, which we should
not execute when an exception occurs, must be placed in the try block. When the exception occurs,
the CLR will create an instance of the Exception class based on the logical error and then throw that
Exception object, which the corresponding catch block will handle.

Catch Block:
The catch block is used to catch the exception that is thrown from its corresponding try block. It has
the logic to take necessary actions on that caught exception. The Catch block syntax in C# looks like a
constructor. It does not take accessibility modifiers, normal modifiers, or return types. It takes only a
single parameter of type Exception or any child class of the parent Exception class. Inside the catch
block, we can write any statement that is legal in .NET, including raising an exception. In this case, we
can stop the abnormal termination of the program, and we can also give the user an understandable
error message so that the user can take necessary action to resolve the error.

Finally Block:

The keyword finally establishes a block that definitely executes the statements placed in it
irrespective of whether any exception has occurred or not. That means the statements that are
placed in finally block are always going to be executed irrespective of whether any exception is
thrown or not, irrespective of whether the thrown exception is handled by the catch block or not.

Syntax to use Exception Handling in C#:

The following image shows the syntax for using exception handling in C#. It starts with the try block,
followed by the catch block, and writing the finally block is optional. You can write any number of
catch blocks for a given try block in C#. This will handle different types of exceptions thrown by the
try block.

Once we use the try-and-catch blocks in our code, the execution takes place as follows:

1. Suppose all the statements under the try block are executed successfully, from the last
statement of the try block. In that case, the control directly jumps to the first statement
present after the catch block (after all catch blocks) without executing the catch block (it
means there is no runtime error in the code).

2. Suppose any of the statements in the try block causes an error from that statement without
executing any other statements in the try block. In that case, the control directly jumps to
the catch blocks, which can handle that exception.
3. If a proper catch block is found that handles the exception thrown by the try block, then the
abnormal termination stops there, executes the code under the catch block, and from there
again, it jumps to the first statement after all the catch blocks.

4. If a matching catch block is not found, the generic catch block will execute to handle the
abnormal termination.

5. If you don’t have the generic catch block and any of the catch blocks cannot handle the
exception, the program execution terminates abnormally.

Example to Handle an Exception using Try-Catch Implementation with Generic Catch Block in C#
The catch block without exception class is called a generic catch, and the generic catch block in C#
can handle any exception raised in the corresponding try block. For a better understanding, please
have a look at the below example. Here, we created the catch block without any Exception class.

using System;

namespace ExceptionHandlingDemo

class Program

static void Main(string[] args)

int Number1, Number2, Result;

try

Console.WriteLine("Enter First Number:");

Number1 = int.Parse(Console.ReadLine());

Console.WriteLine("Enter Second Number:");

Number2 = int.Parse(Console.ReadLine());

Result = Number1 / Number2;

Console.WriteLine($"Result = {Result}");

catch

Console.WriteLine("Some Error Occurred...");

Console.ReadKey();

}
Properties of Exception Class in C#:

ome of the important properties of the Exception Class are properties as follows:

1. Message: This property will store the reason why an exception has occurred.

2. Source: This property will store the application’s name from which the exception has been
raised.

3. HelpLink: This is used to provide a link to any file /URL to give helpful information to the user
about why this exception is raised.

4. StackTrace: This is used to provide more information about the Exception, such as the reason
for the exception, what method and class the exception occurred in, and what line number
the exception occurred at, which helps us resolve the issue.

Exception Handling in C# using Try-Catch Implementation with Exception Catch Block

In the below example, we have created a catch block that takes the Exception class as a parameter.
Within the catch block, we print the exception information using the Exception class properties, i.e.,
Message, Source, StackTrace, and Helplink. As you can see in the below code, we are using the super
Exception class. This class is the superclass of all exception classes so that it will handle all types of
exceptions raised in the try block.

using System;

namespace ExceptionHandlingDemo

class Program

static void Main(string[] args)

int Number1, Number2, Result;

try

Console.WriteLine("Enter First Number:");

Number1 = int.Parse(Console.ReadLine());

Console.WriteLine("Enter Second Number:");

Number2 = int.Parse(Console.ReadLine());

Result = Number1 / Number2;

Console.WriteLine($"Result = {Result}");

catch (Exception ex)

Console.WriteLine($"Message: {ex.Message}");

Console.WriteLine($"Source: {ex.Source}");

Console.WriteLine($"HelpLink: {ex.HelpLink}");
Console.WriteLine($"StackTrace: {ex.StackTrace}");

Console.ReadKey();

You might also like