Introduction
We come across many different types of classes in C# programming.
- Abstract class
- Concrete class
- Sealed class
- Static class
- Instance class
- Partial class
- Inner/Nested class
And the skeleton of a class, the Interface.
Did you ever realize what all these types are and why we use them?
In this article, we are going to explore the different types of classes that OOP language provides and the different keywords used to create all these variants of classes.
Classes and their characteristics
While defining a class we have different keywords, which decide the behavior/type of the class.
- Abstract
- Sealed
- Static
- Partial
We can also mention nothing or use Interface instead of Class.
So there are different types of classes we have heard or come across, and different keywords we use to create a class. But without understanding the real reason why these varieties are introduced and how it will help us, a programmer will never be able to use them efficiently. He/she will end up creating a simple class without any special keyword and not considering any significant type of class.
During the design of your program/application, we might want a class to work as a contract, we might want a class to be defined across multiple files, etc.
Earlier in C++, while programming classes with different characteristic behaviors, there were no keywords in classes. Simply, there were no different types of classes. A simple class with different access modifiers, different implementation of methods and/or different keywords on methods were used. Developers had to keep in mind a lot of things to achieve a characteristic behavior for a class.
C# introduced different keywords that can be used in classes.
A class defined with any of the above keywords has different characteristics and uses.
We will see why these types of classes and keywords are used and what their characteristics are.
Before we begin, let's look at what a class is.
Basic concept of a class in OOP
A class is a blueprint of an entity/object you want to work on in your program. It is what exists on paper. It is not the real entity/object, it just describes the properties of the class and how it will work. It is the object of the class which actually runs in a program to perform an action (get its functional details) using its fields and properties.
A class has data and methods to perform some action on the data. When we write a simple class we declare the data and methods. We declare the methods and write the implementation of it, where we perform action on the data.
Syntax
<access modifier> class ClassName
{
// Data members or member variables
<access modifier> <data type> variable1;
public string Name; // Field
<access modifier> <data type> variable2;
public int Age { get; set; } // Property
// Member methods that may or may not perform actions on the data members
<access modifier> <return type> Method1(parameter_list)
{
// Method body (implementation)
}
public string Greeting(string name)
{
return "Hello " + name;
}
// ...
}
Example. There is a ‘Box’ class that has its properties like Height, Width and Length. The class has the methods ‘Volume’ and ‘SurfaceArea’ which act upon the properties of the ‘Box’ class and return the result. When we create an object of the class, we get the functionality of the box working, using the properties and methods of the box.
Example
public class Box
{
// Data members or member variables
public int Height { get; set; }
public int Width { get; set; }
public int Length { get; set; }
// ...
// Member methods that may or may not perform actions on the data members
public int Volume(Box objBox)
{
int vol = objBox.Length * objBox.Width * objBox.Height;
return vol;
}
public int SurfaceArea(Box objBox)
{
int area = 2 * (objBox.Height * objBox.Width) + 2 * (objBox.Height * objBox.Length) + 2 * (objBox.Width * objBox.Length);
return area;
}
// ...
}
Let’s understand the characteristics of these different types of classes.
Types of Classes and their characteristics
A Simple (basic) Class
Also Called – Instance Class, Concrete Class, Complete Class so, a simple class has methods and their implementation.
- This class can be instantiated to create object(s) and used to perform an action on the data of the class using its methods.
- This class can be used for inheritance. So, it can be used by other classes (as a base class) for inheriting its features.
- This class can inherit from another class. This class (as child class) can also inherit features from any other class.
- Members of the class are accessed through the instance of the class.
- This type of class is also called a concrete class because it is complete. It has defined the methods and also implemented them.
- It is also called an instance class because we can create instances of the class. Furthermore, one can use the functionality of the class only through its object.
- It is a class created without any special keyword.
- It’s the class almost every developer uses.
Characteristics of Simple Class
- Member Implementation (completeness)
- Instantiation (one or multiple)
- Inheriting (from other classes)
- Inheritable (to other classes).
- Member Access.
Interface (Not a class)
It’s a kind of class where we just want to set up certain contracts/rules along with some data. Or say we want to define a Mold/skeleton which should be used by programs to create classes from this Mold/skeleton.
That is, it is a class where we want to define the rules of action (roles in the form of methods which should be followed by the classes which are derived from this). So we just mention the functionality names but not how the functionality will work. How it will work is defined by the inheriting class as per its requirement.
This is a completely incomplete class. That’s why it's not actually a class. It is called an interface.
As the name suggests, an Interface shows what is going to be done or can be done. But the actual implementation of how it is going to be done is somewhere else (i.e. in the class inheriting it).
As it is just a skeleton structure and not complete (and not a class actually), its object creation is of no use. Hence you can never create an object of an Interface.
It is created using the keyword “interface”. The keyword “class” is not used along with it, because it is not actually a class (even partially).
So the scenario in which we want to set up common standards/contract/behaviors for classes (derived class) and just declare the behaviors (non-implemented methods), we use Interface.
Actually it's meant for Inheritance by other classes. A Class with no implementation of methods (Only declaration of rules) + No Instantiation + Inheriting + Inheritable + Member access through derived class Object.
Syntax for Interface Declaration
interface IInterfaceName
{
// Declare Events
// Declare Indexers
// Declare Methods
int InterfaceMethod();
// Declare Properties
}
Syntax for Implementing Interface
class ClassName : IInterfaceName
{
// Class code
// Implement methods of the interface
public int InterfaceMethod()
{
return 0;
}
}
Example. Provides Buttons, Sockets or a Regulator. It is used to regulate/control electric supply to electrical units. Without the electrical units connected to it, the switchboard is of no use. The buttons only work when an electrical unit needs to be controlled, get connected through electrical wiring, and supports power control in itself.
- The switchboard interface provides the following functionalities.
- The Button will have the functionality of releasing the electric supply (ON) and cutting off the electric supply (OFF).
- Socket will have the functionality of providing power supply to any electrical device which has a 3 pinned plug.
- All the units connected to it should be electrical devices.
Abstract Class (Incomplete Class)
We might want a class that sets up common standard/contract/behaviour as an Interface, as well as have common functionality which can be used by derived class.
So an Abstract class is an incomplete class that defines a rule of action (methods) which should be followed by the classes which are derived from this, as well as have certain common features that will be useful for the derived classes.
Here the common features of abstract class are the methods including its implementation, which will be used by derived classes. So these are implemented features to be used by the derived class.
And the rules of action (methods) are the abstract methods for which only signature will be declared, its implementation will be done in the derived class as per requirement of the derived class.
This class is an abstract view of how the derived classes are going to be (or what they are going to do), along with some shared functionality that can use by the derived classes.
Though it has some completely implemented methods, it basically has at least one incomplete (abstract) method which is to be implemented by derived class. As it is an incomplete class its object will be of no use. Hence you can never create an object on an Abstract class (Due to its incompleteness we do not know how much memory will be required).
It is created using the keyword “abstract”, so the scenario in which we want to set up common standards/contract/behaviors for classes (derived class) as well as want to define certain features (method with implementation) which can be used by derived classes we use Abstract class.
Actually meant for Inheritance by other classes, incomplete because it has some methods with implementation.
In simple terms, it is a class with some non-implemented methods + Some implemented methods + No Instantiation + Inheriting + Inheritable + Member access through derived class object.
Syntax for Abstract class Declaration
abstract class AbstractClassName
{
// Declare Events
// Declare Indexers
// Declare Methods
public abstract int AbstractMethod();
// Declare Properties
}
Syntax for Implementing Abstract Class
class ClassName : AbstractClassName
{
public override int AbstractMethod()
{
return 0;
}
}
Example. A computer cabinet provides slots for installing Motherboard, Hard disk, Power Supply, CD Driver, etc. This can be used to assemble a computer of any company and configuration provided its parts get fit into the cabinet (i.e. follows the contract of the Abstract cabinet). The Hard Disk size, motherboard shape, Power Supply shape, and size should match with the slots provided in the cabinet. Apart from providing slots, it also provides common functionality like inbuilt USB ports, LED light indicator, cooling fans, etc.
In scenes of completeness, after this will come a simple class. A class with implementation for all the methods.
Sealed Class
A developer may want the class he is defining to be absolutely complete. Its behaviors (implemented methods) are like a protocol that should never be changed. It should never be used along with other behaviors. Extending it would change the real meaning of the entity (base class). The class we are defining is complete and should never be used by other classes for inheriting its features. This class should be the end of the extending chain. We have a sealed class in C# which can never be derived by any other class. It is called sealed because it is like a perfectly packed (sealed) box which should not be tampered.
Such a class can absolutely be instantiated because it is a complete class. It is created using the “sealed” keyword. So, the scenario in which we want to make our class a uniform and complete, rule which should never be used or altered using derivation, we use Sealed class it blocks inheritance. In simple terms, it is a class with all implemented methods + Inheriting + Non-Inheritable + Member access through own object.
Syntax
sealed class SealedClassName
{
// Declare members
// Declare methods
// ...
}
Example. You can make as many keys (objects) with the same features (shape, size, and thickness), the lock will open. But if you try to change its design by making a bigger, thicker or of different shape, the lock won’t open. The design of the key is complete in itself to open the lock. There is no need to change its features/design. Changing its features will cease it from its basic behavior of opening the lock.
Static Class
In development, there are situations where certain actions of an entity remain the same irrespective of the part of code we are working on. No matter how many (or where) objects we create of a class, the output/action of every method belonging to the class is going to be the same.
We may want a class that has behaviors that are the same (static) throughout the program. As the behavior is going to be the same, then it should not depend on any instance of the class.
A static class is a container that holds static data and static methods which exist for use without the instance of the class.
It has data members and methods which are declared as well as implemented. As the data member and methods are static which does not depends on any instance of the class, object creation is not at all necessary.
Data Members and Methods are directly accessed through the class name. This does not support inheritance, because inheritance is for derived object creation, and static class does not support object.
It is created using the “static” keyword, so the scenario in which we want data and rules/behavior to be independent of objects, we use static class.
In simple terms, it is a class with all implemented methods + Non Inheritable + Non Instantiable + Member access through class name.
Syntax
static class StaticClassName
{
// Declare static members
// Declare static methods
// ...
}
Example. There are many planets and satellites, asteroids and other objects in the solar system, but there is only one star, which is the sun. It exists from the beginning of the solar system. If another sun is added (another object) to the solar system or if the sun changes its behavior (i.e. get derived), it will complete disrupt the working or our current solar system. Life on our planet will be disrupted. Also, all the planets will get disrupted due to imbalance in the gravitational field and solar energy of multiple suns. For every planet to exist properly, the same sun is required.
So these where the different behavioral class types provided by the language, structurally also there may be certain expectations from a class.
Partial Class
Many times, it is cumbersome to keep everything in a class in one place. If there are a lot of data members and member functions, the class becomes less readable. We may want to separate the class content across different files.
Partial class is a class whose content can be kept in different classes with the same name. These classes can be in the same file or across different files, So separate partial classes with the same name constitute a single complete class. We can declare data members in one partial class and use it in other partial class.
We can declare a member function in one partial class and implement the same in other partial class, at runtime all these partial classes are compiled into one single class. If we miss implementing a method, at runtime such a method is discarded. It is created by using the “partial” keyword
For any of the class types we have seen, we can use partial keyword to split it across different partial classes. Not on interface.
So the scenario in which we want to split the content of the class across different classes/files we use partial class.
In ASP.NET, for every webpage we create, a partial class file is created with extension .aspx.cs. The other partial part of this class is kept separately.
Syntax
public partial class ClassName
{
// Declare or implement members
// Declare or implement methods
// ...
}
// 2nd part of the class
public partial class ClassName
{
// Declare or implement members
// Declare or implement methods
// ...
}
Example. A bank has various types of businesses diversified across different sectors. Like SME Banking, Corporate Banking, Wealth Management, Lending, etc. Let the business be across different departments or locations, at the end all business together forms a bank. Even if one business ceases to exist, the bank still exists with other businesses.
Nested Class (Inner Class)
Sometimes there are certain objects/entities whose scope outside a class is of no use or not acceptable. That is, we may need an object of a (small) class which is to be, used just inside a specific class. Additionally, a class may be unique and small, and useful only to a specific class. So if we have such an entity, we can write such a class inside the required class. A class inside of a class, that’s why is has the name nested class.
The scope of a nested class is within the containing class. Nested class can have any of all the access modifiers, it can access even private members of the outer class while having the full power of a class itself.
The outer class cannot access the members of the inner class directly. It has to be through object creation. The outer class cannot access private members of the inner class.
Also they can be private which allows for some pretty powerful encapsulation in certain circumstances. Making it usable only within the containing class.
If the Outer class is inherited by some class, then the inner class is also inherited through the outer class. No special keyword is required to define such a class.
Syntax
class OuterClass
{
// Declare members
// Declare methods
class InnerClass
{
// Declare members
// Declare methods
// ...
}
}
Example. The boxes are nested one inside the other. Any outer box cannot touch the inner side of the box inside it. The inner box can move around inside the outer box.
Consider the inner sides of boxes as private properties and the outer sides as public properties. A smaller box placed inside any bigger box can touch the inner (private properties) side of the bigger (outer) box, but the bigger box can touch only the outer (public properties) sides of the smaller (inner) box.
The outer box can never go inside the inner box to access its private properties.
There are other types of classes that you may come across, but are not used in C#.
Virtual Class
With multiple inheritance allowed in OOP, there are chances that a class can be derived from multiple base classes which are actually derived from the same super base class.
So a virtual class is a super base class where a derived class has multiple copies of super base class through multiple inheritance (using multiple base classes). Supported in C++ and Java.
In such a scenario, there will be multiple copies of such a super base class with the derived class. This is called the DIAMOND problem.
By marking such a base class as virtual during inheritance, only one copy of the super base class will be maintained while creating the object of the derived class.
In C#, if there is conflicting method in child class and parent class (Not virtual class) we create a virtual method in the parent class and override this method in child class.
Virtual classes are functional classes that can be instantiated or extended without the need for overriding methods.
Example. Wedding Reception invitation from two of your best friends getting married.
When you get a wedding invitation from both the bride and groom, as both are your best friends, you can’t appear twice at the wedding. There will be only one copy for you at the reception.
A double invitation doesn’t mean that you can eat twice at the reception.
Local Class
There are scenarios where a class/entity will be used within a block of code only and nowhere else. Usually within a particular function.
So, there is no need to create a separate class at namespace or class level as it is not going to be used anywhere.
Local classes are classes that are defined in a block, which is a group of zero or more statements between balanced braces. Typically defined in the body of a method.
This limits the reference of the class where it is defined i.e. within the code block enclosed { }. No special keyword is required to define such a class. Supported in C++ and Java.
Example. BEST can run only within the boundary of the city. It cannot have scope outside the city.
If we consider State as a Class and City as function (OR Local boundaries created using braces {..}). Then the BEST bus has the functionality of moving locally within the city only. Whereas an ST bus which is State level transport can move throughout the state. We can consider ST bus as a nested class and the BEST bus as a local class.
Now, what if we have an expectation from a class which any of the above type of keywords do not satisfy.
Example: We want the only one object of a class to be created.
Answer is Design Patterns. Example Singleton Design Pattern
Conclusion
So in C++, the various ways to create different class’s characteristics can be considered as Design Patterns then.
In C# these Design Patterns are easily available with keywords given by the language, rest everything is handled by the compiler and CLR.
This is how our programming languages evolve with different needs arising. Maybe in new programming languages or in advanced versions of C#, we might have keywords on classes that will satisfy today's design pattern needs.
We might have a keyword "singleton" on class ;).