C# is a simple, general-purpose, modern, object-oriented programming language.In this post, we will be discussing about Object-oriented programming in C#, and I will provide you description about each oops concept in C# with example code to make it more clear.

But before we begin to explore OOPS in C#, first discuss what is OOP?

object-oriented-programming-concepts-oops-concepts-in-c-sharp-with-example-min.png

What is Object-Oriented Programming (OOP)?

As computers increase in processing power, the software they execute becomes more complex. This increased complexity comes at a cost of large programs with huge codebases that can quickly become difficult to understand, maintain and keep bug-free.

Object-oriented programming (OOP) tries to alleviate this problem by creating networks of objects, each like a small software 'machine'. These objects are naturally smaller entities, simplifying the development task of each unit. However, when the objects co-operate in a system, they become the building blocks of much more complex solution.

Object-oriented programming is about modelling real world objects or concepts as objects in an application:

  • An object is something – a person
  • An object has data – a person has a name
  • An object performs actions – a person can introduce itself

Consider the motor car. If a car were designed as a single machine, it would be seen as hugely complex with lots of opportunities for failure. However, when broken down into its constituent parts, such as wheels, pedals, doors, etc. the individual design items become simpler.

Each part (or object) is created independently, tested carefully and then assembled into the final product. The creation of the parts can be simplified further when they are broken down into even simpler items. For example, when each door is considered as being composed of an outer panel, handle, inner panel and window.

The car example is analogous to the object-oriented software. Rather than writing a huge program to create, for example, a project management system, the solution is broken into real-world parts such as project, task, estimate, actual, deliverable, etc. Each of these can then be developed and tested independently before being combined.

There are some basic programming concepts in OOP:

  • Abstraction - The abstraction is simplifying complex reality by modeling classes appropriate to the problem.
  • Polymorphism - The polymorphism is the process of using an operator or function in different ways for different data input.
  • Encapsulation - The encapsulation hides the implementation details of a class from other objects. 
  • Inheritance - The inheritance is a way to form new classes using classes that have already been defined.

OOPS Concepts, Features & Fundamentals in C# with example

OOPS contains list of elements that are very helpful to make object oriented programming stronger. Here is the list of OOPS concepts that we can implement in all major programming languages like c#.

1. Class

A class is a collection of objects and represents description of objects that share same attributes and actions.

A class describes in abstract all of the characteristics and behaviour of a type of object.

Once instantiated, an object is generated that has all of the methods, properties and other behaviour defined within the class.

A class should not be confused with an object. The class is the abstract concept for an object that is created at design-time by the programmer. The objects based upon the class are the concrete instances of the class that occur at run-time. For example, the Car class will define that all cars have a make, model and colour.

Here is the syntax and declaration example of Class:

namespace ClassTest
{
     public class Vehicle
    {
       //your code goes here..
    } 
}

Instantiating the Class

static void Main(string[] args)
{
    Vehicle car = new Vehicle();
    Console.WriteLine(car.ToString());  // Outputs "ClassTest.Vehicle"
}

2. Objects

Objects are basic building blocks of a C# OOP program. An object is a combination of data and methods. The data and the methods are called members of an object. In an OOP program, we create objects. These objects communicate together through methods. Each object can receive messages, send messages and process data.

There are two steps in creating an object. First, we define a class. A class is a template for an object. It is a blueprint which describes the state and behavior that the objects of the class all share. A class can be used to create many objects. Objects created at runtime from a class are called instances of that particular class.

For example, A “Bike” usually has common elements such as bike color, engine, mileage etc. In OOP terminology these would be called as a Class Properties or Attributes of a Bike object. Here is the example of Object:

public class Bike
{
       //This is the class that contains all properties and behavior of an object

       //here is some properties of class Bike
       public string color;
       public string engine;
       public int mileage;

       //here is some behavior of class Bike
       public string GetColor()
       {
               return "red";
       }
       public int GetMileage()
       {
               return 65;
       }
}

Now, to access Bike class, we need create the object of the Bike class and then access it Methods and objects.

//It also considered as an "Instance of a Bike Class"
Bike objBike = new Bike();

//Accessing Bike class methods
objBike.GetColor();
objBike.GetMileage();

3. Method

Methods are functions defined inside the body of a class. They are used to perform operations with the attributes of our objects. Methods bring modularity to our programs.

Methods are essential in the encapsulation concept of the OOP paradigm. For example, we might have a Connect() method in our AccessDatabase class. We need not to be informed how exactly the method Connect() connects to the database. We only have to know that it is used to connect to a database. This is essential in dividing responsibilities in programming, especially in large applications.

Objects group state and behavior, methods represent the behavioral part of the objects.

using System;

public class Circle 
{
    private int radius; 

    public void SetRadius(int radius)
    {
        this.radius = radius;
    }

    public double Area()
    {
        return this.radius * this.radius * Math.PI;
    }
}

public class Methods
{
    static void Main()
    {
        Circle c = new Circle();
        c.SetRadius(5);

        Console.WriteLine(c.Area());
    }
}

In the code example, we have a Circle class. We define two methods.

private int radius;

We have one member field. It is the radius of the circle. The private keyword is an access specifier. It tells that the variable is restricted to the outside world. If we want to modify this variable from the outside, we must use the publicly available SetRadius() method. This way we protect our data.

public void SetRadius(int radius)
{
    this.radius = radius;
}

This is the SetRadius() method. The this variable is a special variable which we use to access the member fields from methods. The this.radius is an instance variable, while the radius is a local variable, valid only inside the SetRadius() method.

Circle c = new Circle();
c.SetRadius(5);

We create an instance of the Circle class and set its radius by calling the SetRadius() method on the object of the circle. We use the dot operator to call the method.

public double Area()
{
    return this.radius * this.radius * Math.PI;
}

The Area() method returns the area of a circle.

4. Encapsulation

Encapsulation is the process of keeping or enclosing one or more items within a single physical or logical package. In object oriented programming methodology it prevents access to implementation details.

Encapsulation is implemented by using access specifiers. An access specifier defines the scope and visibility of a class member. Available access specifiers are public, private, protected, internal etc.

How to achieve encapsulation?
We can achieve Encapsulation by using private access modifier as shown in below example method.

private string GetEngineMakeFormula()
{
       private string formula = "a*b";
       return formula;
} 

Example – [Encapsulation]

public class Bike
{
       public int mileage = 65;
       public string color = "Black";
       private string formula = "a*b";

       //Its public – so accessible outside class
       public int GetMileage()
       {
               return mileage;
       }

       //Its public – so accessible outside class
       public string GetColor()
       {
               return color;
       }

       //Its private – so not accessible outside class
       private string GetEngineMakeFormula()
       {
               return formula;
       }
}

public class Program
{
       public static void Main(string[] args)
       {
               Bike objBike = new Bike();
               Console.WriteLine("Bike mileage is : " + objBike.GetMileage()); //accessible outside "Bike"
               Console.WriteLine("Bike color is : " + objBike.GetColor()); //accessible outside "Bike"
               //we can't call this method as it is inaccessible outside "Bike"
               //objBike.GetEngineMakeFormula(); //commented because we can't access it
               Console.Read();
       }
}

Output: https://dotnetfiddle.net/scAgvm

Bike mileage is : 65
Bike color is : Black

5. Abstraction

Abstraction is the process of providing only essential information to the outside real world and hiding overall background details to present an object. It relies on the separation of interface and implementation.

For example, we continue with “Bike” as an example, we have no access to the piston directly, we can use start button to run the piston. Just imagine if a bike manufacturer allows direct access to piston, it would be very difficult to control actions on the piston. That’s the reason why a bike provider separates its internal implementation from its external interface.

public class Bike
{
       public int mileage = 65;
       public string color = "Black";
       private string formula = "a*b";

       //Its public – so accessible outside class
       public int GetMileage()
       {
               return mileage;
       }

       //Its public – so accessible outside class
       public string GetColor()
       {
               return color;
       }

       //Its private – so not accessible outside class
       private string GetEngineMakeFormula()
       {
               return formula;
       }

       //Its public – so accessible outside class
       public string DisplayMakeFormula()
       {
               //"GetEngineMakeFormula()" is private but accessible and limited to this class only
               return GetEngineMakeFormula();
       }
}

public class Program
{
       public static void Main(string[] args)
       {
               Bike objBike = new Bike();
               Console.WriteLine("Bike mileage is : " + objBike.GetMileage()); //accessible outside "Bike"
               Console.WriteLine("Bike color is : " + objBike.GetColor()); //accessible outside "Bike"
               //we can't call this method as it is inaccessible outside "Bike"
               //objBike.GetEngineMakeFormula(); //commented because we can't access it
               Console.WriteLine("Bike color is : " + objBike.DisplayMakeFormula()); //accessible outside
               Console.Read();
       }
}

As you can see from the above code that necessary methods and properties exposed using public access modifier and unnecessary methods and properties are hidden using private access modifier. This way we can implement abstraction or we can achieve abstraction in our code or web application.

Also Read: Abstract class in C#

6. Inheritance

The inheritance is a way to form new classes using classes that have already been defined. The newly formed classes are called derived classes, the classes that we derive from are called base classes. Important benefits of inheritance are code reuse and reduction of complexity of a program. The derived classes (descendants) override or extend the functionality of the base classes (ancestors).

using System;

public class Being 
{
    public Being()
    {
        Console.WriteLine("Being is created");
    }
}

public class Human : Being
{
    public Human()
    {
        Console.WriteLine("Human is created");
    }
}

public class Inheritance
{
    static void Main()
    {
        new Human();
    }
}

In this program, we have two classes. A base Being class and a derived Human class. The derived class inherits from the base class.

public class Human : Being

In C#, we use the colon (:) operator to create inheritance relations.

new Human();

We instantiate the derived Human class.

Output of the above Inheritance code will be

Being is created
Human is created

We can see that both constructors were called. First, the constructor of the base class is called, then the constructor of the derived class.

Also read :Interface in C# (With Example)

7. Polymorphism

The polymorphism is the process of using an operator or function in different ways for different data input.

In practical terms, polymorphism means that if class B inherits from class A, it does not have to inherit everything about class A; it can do some of the things that class A does differently.

In general, polymorphism is the ability to appear in different forms. Technically, it is the ability to redefine methods for derived classes. Polymorphism is concerned with the application of specific implementations to an interface or a more generic base class.

Polymorphism is the ability to redefine methods for derived classes.

There are two types of polymorphism in C#: compile time polymorphism and runtime polymorphism.

Compile time polymorphism is achieved by method overloading and operator overloading in C#. It is also known as static binding or early binding.

Example of Compile time polymorphism

public class clsCalculation
{

        public int Add(int a, int b)
        {
            return a + b;
        }

        public double Add(int z, int x, int c)
        {
            return z + x + c;
        }
       
}

In above code we have a class "clsCalculation" having two functions with same name "Add" but having different input parameters.

First function is with 2 parameters and second function having 3 parameters. So this type of polymorphism is also known as method overloading.

It is a compile time polymorphism because compiler already knows what type object it is linking to, what are the methods it is going to call it. So linking a method during a compile time also called as Early binding.

Runtime polymorphism in achieved by method overriding which is also known as dynamic binding or late binding. Example of the runtime polymorphism is as below

using System;

public abstract class Shape
{
    protected int x;
    protected int y;
    
    public abstract int Area();
}

public class Rectangle : Shape
{    
    public Rectangle(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    public override int Area()
    {
        return this.x * this.y;
    }
}

public class Square : Shape 
{
    public Square(int x)
    {
        this.x = x;
    }

    public override int Area()
    {
        return this.x * this.x;
    }
}

public class Polymorphism
{
    static void Main()
    {
        Shape[] shapes = { new Square(5), 
            new Rectangle(9, 4), new Square(12) }; 

        foreach (Shape shape in shapes)
        {
            Console.WriteLine(shape.Area());
        }
    }
}

In the above program, we have an abstract Shape class. This class morphs into two descendant classes: Rectangle and Square. Both provide their own implementation of the Area() method. Polymorphism brings flexibility and scalability to the OOP systems.

public override int Area()
{
    return this.x * this.y;
}
...
public override int Area()
{
    return this.x * this.x;
}

The Rectangle and the Square classes have their own implementations of the Area() method.

Shape[] shapes = { new Square(5), 
    new Rectangle(9, 4), new Square(12) };

We create an array of three Shapes.

foreach (Shape shape in shapes)
{
    Console.WriteLine(shape.Area());
}

We go through each shape and call the Area() method on it. The compiler calls the correct method for each shape. This is the essence of polymorphism.