Diving in OOP (Day 4): Polymorphism and Inheritance (All About Abstract Classes in C#)


1. Introduction

We learnt a lot about polymorphism and inheritance. In this article of the series “Diving in OOP”, we’ll discuss about the most hot and exciting topic of OOP in C#, i.e., Abstract Classes. The concept of Abstract classes is the same for any other language, but in C# we deal with it in a bit different way. Abstract classes play a different and very interesting role in polymorphism and inheritance. We’ll cover all the aspects of abstract classes with our hands-on lab and theory as an explanation to what output we get. We’ll also list down points to remember at the end of the article.

Pre-requisites

Wonder, we are dealing with the fourth part of our learning objective. Now my only expectation with my readers is to enjoy the series.

2. Roadmap

Let’s recall our road map:

3. Abstract Classes

Let’s get the definition from MSDN:

“The abstract keyword enables you to create classes and class members that are incomplete and must be implemented in a derived class. An abstract class cannot be instantiated. The purpose of an abstract class is to provide a common definition of a base class that multiple derived classes can share. For example, a class library may define an abstract class that is used as a parameter to many of its functions, and require programmers using that library to provide their own implementation of the class by creating a derived class.
Abstract classes may also define abstract methods. This is accomplished by adding the keyword abstract before the return type of the method.”

4. Abstract Classes in Action

Add a console application named “InheritanceAndPolymorphism” in your Visual Studio. You’ll get a class namedProgram.cs, just add one more class named ClassA.cs, note that the ClassA should be marked abstract, and the following code to ClassA.cs and Program.cs:
using System;

namespace InheritanceAndPolymorphism
{
public abstract class ClassA
{

}

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassA classA = new ClassA();
Console.ReadKey();
}
}
}

Compile the code.

Output

Compile time error: Cannot create an instance of the abstract class or interface 'InheritanceAndPolymorphism.ClassA'
 
Point to remember: We cannot create an object of abstract class using new keyword.
Now we go into understanding the concept. No power can stop abstract keyword to be written before a class. It acts as a modifier to the class. We cannot create an object of abstract class using new keyword. Seems that the class is useless for us as we cannot use it for other practical purposes as we used to do.

5. Non Abstract Method Definition in Abstract Class

Let’s add some code to our abstract class:
    /// <summary>
    /// Abstract class ClassA
    /// </summary>
    public abstract class ClassA
    {
        public int a;
        public void XXX()
        {

}
}

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassA classA = new ClassA();
Console.ReadKey();
}
}

We again see the error that we encountered earlier. Again, it reminds that we cannot use new if we have already used an abstract modifier.

6. Abstract Class Acting as a Base Class

Let’s add one more class now:
    /// <summary>
    /// Abstract class ClassA
    /// </summary>
    public abstract class ClassA
    {
        public int a;
        public void XXX()
        {

}
}

/// <summary>
/// Derived class.
/// Class derived from abstract class ClassA
/// </summary>
public class ClassB:ClassA
{

}

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}

We get no error? A class can be derived from abstract class. Creating an object of ClassB does not gives us any error.
 
Point to remember: A class can be derived from an abstract class.
 
Point to remember: A class derived from an abstract class can create an object.

7. Non Abstract Method Declaration in Abstract Class

Another scenario:
    /// <summary>
    /// Abstract class ClassA
    /// </summary>
    public abstract class ClassA
    {
        public int a;
        public void XXX()
        {

}

public void YYY();
}

/// <summary>
/// Derived class.
/// Class derived from abstract class ClassA.
/// </summary>
public class ClassB:ClassA
{

}

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}

We just declared a method named YYY() in our abstract class ClassA.
Compile the code, we get:

Output

Compile time error: 'InheritanceAndPolymorphism.ClassA.YYY()' 
must declare a body because it is not marked abstract, extern, or partial
 
InheritanceAndPolymorphism is the namespace I used for my console application so you can ignore that, no need to confuse with the logic.
In the above code, we just added a method declaration in the abstract class. An abstract method indicates that the actual definition or code of the method is created somewhere else. The method prototype declared in abstractclass must also be declared abstract as per the rules of C#.

8. Abstract Method Declaration in Abstract Class

Just make the method YYY() as abstract in ClassA:
    /// <summary>
    /// Abstract class ClassA
    /// </summary>
    public abstract class ClassA
    {
        public int a;
        public void XXX()
        {

}

abstract public void YYY();
}

/// <summary>
/// Derived class.
/// Class derived from abstract class ClassA.
/// </summary>
public class ClassB:ClassA
{

}

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}

Output

Compiler error: 'InheritanceAndPolymorphism.ClassB' does not implement 
inherited abstract member 'InheritanceAndPolymorphism.ClassA.YYY()'
 
Point to remember: If we declare any method as abstract in our abstract class, then it’s the responsibility of the derived class to provide the body of that abstract method, unless a body is provided for that abstract method, we cannot create an object of that derived class.
In the above mentioned scenario, we declared method YYY() as abstract in ClassA. Since ClassB derives fromClassA, now it becomes the responsibility of ClassB to provide the body of that abstract method, else we cannot create an object of ClassB.

9. Abstract Method Implementation in Derived Class

Now provide a body of method YYY() in ClassB. Let’s see what happens:
    /// <summary>
    /// Abstract class ClassA
    /// </summary>
    public abstract class ClassA
    {
        public int a;
        public void XXX()
        {

}

abstract public void YYY();
}

/// <summary>
/// Derived class.
/// Class derived from abstract class ClassA.
/// </summary>
public class ClassB:ClassA
{
public void YYY()
{

}
}

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}

Everything seems fine now, but no? Compile the code, what we get:

Output

Two compile time errors this time:
Compile time error: 'InheritanceAndPolymorphism.ClassB' does not implement 
inherited abstract member 'InheritanceAndPolymorphism.ClassA.YYY()'

Compile time warning: ‘InheritanceAndPolymorphism.ClassB.YYY()’ hides
inherited member ‘InheritanceAndPolymorphism.ClassA.YYY()’.

To make the current member override that implementation, add the override keyword. Otherwise add the newkeyword.
We have been continuously trying to compile our code, but no success till now. The compiler error indicates clearly that both of our base and derived class contains the same method named YYY().
If both our derived class and base class contain the method with the same name, always an error occurs. The only way to overcome this error is derived class explicitly add the modifier override to its method signature. We have already discussed such scenarios in our previous parts of the articles of Diving in OOP series.
Let’s add the override keyword before derived class method YYY().
/// <summary>
    /// Abstract class ClassA
    /// </summary>
    public abstract class ClassA
    {
        public int a;
        public void XXX()
        {

}

abstract public void YYY();
}

/// <summary>
/// Derived class.
/// Class derived from abstract class ClassA.
/// </summary>
public class ClassB:ClassA
{
public override void YYY()
{

}
}

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}

We get no warning or error now?

10. Abstract Method Implementation in Derived Class with Different Return Type

Let’s just change the return type of the method YYY() in derived class:
  /// <summary>
    /// Abstract class ClassA
    /// </summary>
    public abstract class ClassA
    {
        public int a;
        public void XXX()
        {

}

abstract public void YYY();
}

/// <summary>
/// Derived class.
/// Class derived from abstract class ClassA.
/// </summary>
public class ClassB:ClassA
{
public override int YYY()
{

}
}

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}

We changed return type of method YYY from void to int in derived class. Compile the code.

Output

Compile time error: 'InheritanceAndPolymorphism.ClassB.YYY()': return type must be 'void' 
to match overridden member 'InheritanceAndPolymorphism.ClassA.YYY()'
Therefore one more constraint.
 
Point to remember: When we override an abstract method from a derived class, we cannot change the parameters passed to it or the return type irrespective of the number of methods declared as abstract in abstractclass.
Let’s see the implementation of the second line mentioned in “point to remember”,
    /// <summary>
    /// Abstract class ClassA
    /// </summary>
    public abstract class ClassA
    {
        public int a;
        public void XXX()
        {

}

abstract public void YYY();
abstract public void YYY1();
abstract public void YYY2();
abstract public void YYY3();
}

/// <summary>
/// Derived class.
/// Class derived from abstract class ClassA.
/// </summary>
public class ClassB:ClassA
{
public override int YYY()
{

}
}

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}

Compiler error:
'InheritanceAndPolymorphism.ClassB' does not implement 
inherited abstract member 'InheritanceAndPolymorphism.ClassA.YYY3()'

‘InheritanceAndPolymorphism.ClassB’ does not implement inherited
abstract member ‘InheritanceAndPolymorphism.ClassA.YYY2()’

‘InheritanceAndPolymorphism.ClassB’ does not implement inherited
abstract member ‘InheritanceAndPolymorphism.ClassA.YYY1()’

If we implement these three methods in derived class, we’ll get no error.
Point to remember: An abstract class means that the class is incomplete and cannot be directly used. Anabstract class can only be used as a base class for other classes to derive from.

11. Variable Initialization in Abstract Class

Therefore as seen earlier, we get an error if we use a new keyword on an abstract class. If we do not initialize a variable in an abstract class like we used a, it will automatically have a default value of 0 which is what the compiler kept warning us about. We can initialize int variable a of ClassA to any value we wish. The variables in abstractclass act similar to that in any other normal class.

12. Power of Abstract Class

Whenever a class remains incomplete, i.e., we do not have the code for some methods, we mark those methodsabstract and the class is marked abstract as well. And so, we can compile our class without any error or blocker. Any other class can then derive from our abstract class but they have to implement the abstract, i.e., our incomplete methods from abstract class.
Abstract therefore enables us to write code for a part of the class and allows the others (derived classes) to complete the rest of the code.

13. Abstract Method in Non Abstract Class

Let’s take another code block:
    /// <summary>
    /// Abstract class ClassA
    /// </summary>
    public class ClassA
    {
        public int a;
        public void XXX()
        {

}

abstract public void YYY();
}

/// <summary>
/// Derived class.
/// Class derived from abstract class ClassA.
/// </summary>
public class ClassB:ClassA
{
public override void YYY()
{

}
}

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}

Compile the code.

Output

Compiler error: 'InheritanceAndPolymorphism.ClassA.YYY()' is abstract 
but it is contained in non-abstract class 'InheritanceAndPolymorphism.ClassA'
We just removed abstract keyword from class ClassA. The error clearly conveys a message that if a single method is marked abstract in a class, then the class will have to be abstract as well.
 
Point to remember: If a class has even a single abstract method, then the class has to be declared abstract as well.
 
Point to remember: An abstract method also cannot use the modifiers such as static or virtual.
We can only have the abstract method in an abstract class. Any class that derives from abstract class has to give implementation to its abstract method. By default, the modifier new gets added to the derived class method, that makes it a new/different method.

14. Abstract Base Method

    /// <summary>
    /// Abstract class ClassA
    /// </summary>
    public abstract class ClassA
    {
        public int a;
        public void XXX()
        {

}

abstract public void YYY();
}

/// <summary>
/// Derived class.
/// Class derived from abstract class ClassA.
/// </summary>
public class ClassB:ClassA
{
public override void YYY()
{
base.YYY();
}
}

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}

Output

Compile time error : Cannot call an abstract base member: 
'InheritanceAndPolymorphism.ClassA.YYY()'
We cannot call the method YYY() from the base class ClassA as it does not carry any implementation/code along with it and has also been declared abstract. Common sense prevails? and C# off course does not allow us to call a method that does not contain code.

15. Abstract Class Acting as Derived as Well as Base Class

Let’s modify our code a bit, and prepare our class structure something as follows:
    /// <summary>
    /// Base class ClassA
    /// </summary>
    public class ClassA
    {
        public virtual void XXX()
        {
            Console.WriteLine("ClassA XXX");
        }
    }

/// <summary>
/// Derived abstract class.
/// Class derived from base class ClassA.
/// </summary>
public abstract class ClassB:ClassA
{
public new abstract void XXX();
}

public class ClassC:ClassB
{
public override void XXX()
{
System.Console.WriteLine(ClassC XXX”);
}
}

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassA classA = new ClassC();
ClassB classB = new ClassC();
classA.XXX(); classB.XXX();
}
}

Compile the code, and run.

Output

ClassA XXX
ClassC XXX
We created a base class named ClassA that is not abstract and added a virtual method XXX to it. Since the method is non abstract but marked virtual so it has to be overridden in its deriving class. We added one more class named ClassB and marked that class abstract, note that this class is derived from ClassA. So this class has a choice to override the method marked as virtual in base class. But we’ll do something different and tricky,
We marked XXX method in this derived class as new abstract, and did not give anybody to this method. Now what? We will add one more class ClassC, that will derive from ClassBClassC has no choice but to override the methodXXX. Therefore we override the method XXX in ClassC.
In main method, we created two objects ClassA classA = new ClassC(); and ClassB classB = new ClassC();
First object looks like that of ClassC but refers to ClassA and second one again seems to be like ClassC but refers to ClassB.
In case of classA.XXX() will definitely first look into the class ClassA. Here, it finds the method XXX marked as virtual. These kind of scenarios we have already taken n number of times in our earlier articles where we discussed about run time polymorphism . C# will then crawl over to class ClassB. Here it gets shocked that the method XXX()is abstract, i.e., there is no code or implementation for method XXX() and also that it is a method marked as new, thus severing all links with the base class. And so flow halts and all and the method XXX() from ClassA gets executed.
In the case of b.XXX()(), since the method is new, the links to the base class gets broken, we are left with no choice but to invoke the method from ClassC as it says override.
We cannot replace the modifier new with the keyword override for the method XXX() in abstract class ClassB.
Let’s replace the override modifier in ClassC with “new” like:
 public class ClassC:ClassB
     {
        public new void XXX()
        {
            System.Console.WriteLine("ClassC XXX");
        }
     }

Output

Compile time error: 'InheritanceAndPolymorphism.ClassC' does not implement 
inherited abstract member 'InheritanceAndPolymorphism.ClassB.XXX()'
The error indicates that as there is no code for the method XXX. Remember the XXX() of class ClassA has nothing to do at all with that of ClassB and ClassC.
Also there is one more point to remember.
 
Point to remember: Virtual methods run slower that non virtual methods.

16. Can Abstract Class be Sealed?

Let’s take this final question into our consideration. Let’s test this too with an example.
    /// <summary>
    /// sealed abstract class ClassA
    /// </summary>
    public sealed abstract class ClassA
    {
        public abstract void XXX()
        {
            Console.WriteLine("ClassA XXX");
        }
    }

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
}
}

Compile the code.

Output

Compile time error: 'InheritanceAndPolymorphism.ClassA': 
an abstract class cannot be sealed or static
And so we get two points to remember.
 
Point to rememberAbstract class cannot be sealed class.
 
Point to rememberAbstract class cannot be a static class.

17. Points to Remember

Let’s sum up all the points to remember:
  1. We cannot create an object of abstract class using new keyword.
  2. A class can be derived from an abstract class.
  3. Class derived from an abstract class can create an object.
  4. If we declare any method as abstract in our abstract class, then it’s the responsibility of the derived class to provide the body of that abstract method, unless a body is provided for that abstract method, we cannot create an object of that derived class.
  5. When we override an abstract method from a derived class, we cannot change the parameters passed to it or the return type irrespective of the number of methods declared as abstract in abstract class.
  6. An abstract class means that the class is incomplete and cannot be directly used. An abstract class can only be used as a base class for other classes to derive from.
  7. If a class has even a single abstract method, then the class has to be declared abstract as well.
  8. An abstract method also cannot use the modifiers such as static or virtual.
  9. Virtual methods run slower that non virtual methods.
  10. Abstract class cannot be sealed class.
  11. Abstract class cannot be a static class.

18. Conclusion

With this article, we complete our understanding of inheritance and polymorphism. We have covered almost all the aspects of Polymorphism and Inheritance. Abstract classes are one of my favorites so I just wanted to take them separately. I hope my readers enjoyed this article too and learnt about abstract classes in C#.
In my upcoming articles of the series, we’ll be discussing about other OOP features in the C# way with full hands-on lab and lot of discussion.
Keep coding and enjoy reading. 
Also do not forget to rate/comment/like my article if it helped you by any means. This helps me to get motivated and encourages me to write more and more.

Read more:

Other Series

My other series of articles:

For more informative articles visit my Blog.

For more technical articles you can reach out to CodeTeddy.

Diving in OOP (Part 2) : Polymorphism and Inheritance (Inheritance)


Introduction

In our first part of the article, we learned about different scenarios of method overloading and did lots of interesting hands on too. My article in the second part of the series will focus solely on inheritance concept in OOP. Let’s define Inheritance using some bullet points:

Roadmap

We still stick to our roadmap that we defined before starting the series for learning OOP:

Note: Each and every code snippet written in this article is tried and tested.

Inheritance in Action

OK. Let’s do some hands on. Create a console application and name it InheritanceAndPolymorphism. Add a class named ClassA and a class named ClassB, with the following code:
ClassA:

class ClassA
{

}

ClassB:

class ClassB
{
public int x = 100;
public void Display1()
{
Console.WriteLine(ClassB Display1″);
}
public void Display2()
{
Console.WriteLine(ClassB Display2″);
}
}

We see classClassA is empty and we added two methods in class ClassB, i.e. Display1 and Display2. We also have a variable declared and defined with a value 100.
Now in the main method of Program.cs, write the following code:

Program.cs

class Program
    {
        static void Main(string[] args)
        {

ClassA a = new ClassA();
a.Display1();
}
}

If we run the code, we immediately result in the compile time error.
 
Error'InheritanceAndPolymorphism.ClassA‘ does not contain a definition for ‘Display1‘ and no extension method ‘Display1‘ accepting a first argument of type ‘InheritanceAndPolymorphism.ClassA‘ could be found (are you missing a using directive or an assembly reference?)
i.e. Too obvious, we don’t have definition of Display1 method in ClassA, nor can we access the same method usingClassA instance because it is not derived from any such class like ClassB that contains Display1 method. The class ClassA does not contain any code or variable defined. An empty class does not throw any error as we are able to instantiate an object that looks like a (instance of ClassA). The error comes about because the class ClassA has no method called Display1. However the class ClassB has a method named Display1. Guess how fun it could be if we are allowed to access all the code of classB from ClassA itself.
Just derive the class ClassA from ClassB using : operator as code shown below:
ClassA:

class ClassA:ClassB
{

}

ClassB:

class ClassB
{
public int x = 100;
public void Display1()
{
Console.WriteLine(ClassB Display1″);
}
public void Display2()
{
Console.WriteLine(ClassB Display2″);
}
}

Program.cs

class Program
    {
        static void Main(string[] args)
        {
            ClassA a = new ClassA();
            a.Display1();
            Console.ReadKey();
        }
    }
And now run the code as it was, we get an output now.

Output

ClassB Display1
i.e. now ClassA can access the inherited public methods of ClassB. The error vanishes and the Display1 inClassB gets invoked. If after the name of a class we specify : ClassB i.e., the name of another class, a lot changes at once. ClassA is now said to have been derived from ClassB. What that means is all the code we wrote in ClassBcan now be accessed and used in ClassA. It is if we actually wrote all the code that is contained in ClassB in ClassA. If we had created an instance that looks like that of ClassB, everything that the instance could do, now an instance ofClassA can also do. But we have not written a line of code in ClassA. We are made to believe that ClassA has one variable x and two functions Display1 and Display2 as ClassB contains these two functions. Therefore, we enter
into the concepts of inheritance where ClassB is the base class, ClassA the derived class.
Let’s take another scenario. Suppose we get into a situation where ClassA also has a method of same name as of inClassB. Let’s define a method Derive1 in ClassA too, so our code for classA becomes:
class ClassA:ClassB
    {
        public void Display1()
        {
            System.Console.WriteLine("ClassA Display1");
        }
    }

ClassB:

class ClassB
{
public int x = 100;
public void Display1()
{
Console.WriteLine(ClassB Display1″);
}
public void Display2()
{
Console.WriteLine(ClassB Display2″);
}
}

Now if we run the application using the following code snippet for Program.cs class:
class Program
    {
        static void Main(string[] args)
        {
            ClassA a = new ClassA();
            a.Display1();
            Console.ReadKey();
        }
    }
The question is what will happen now? What will be the output? Will there be any output or any compilation error. Ok, let’s run it.
We get Output:
ClassA Display1
But did you notice one thing, we also got a warning when we run the code:
 
Warning: ‘InheritanceAndPolymorphism.ClassA.Display1()‘ hides inherited member ‘InheritanceAndPolymorphism.ClassB.Display1()‘. Use the new keyword if hiding was intended.
 
Point to remember: No one can stop a derived class to have a method with the same name already declared in its base class.
So, ClassA undoubtedly can contain Display1 method, that is already defined with the same name in ClassB.
When we invoke a.Display1(), C# first checks whether the class ClassA has a method named Display1. If it does not find it, it checks in the base class. Earlier Display1 method was only available in the base class ClassB and hence got executed. Here, since it is there in ClassA, it gets called from ClassA and not ClassB.
 
Point to remember: Derived classes get a first chance at execution, then the base class.
The reason for this is that the base class may have a number of methods and for various reasons, we may not be satisfied with what they do. We should have the full right to have our copy of the method to be called. In other words, the derived classes methods override the ones defined in the base class.
What happens if we call base class Display1 method too with base keyword in derived class, i.e., by usingbase.Display1(), so our ClassA code will be:
ClassA:

class ClassA:ClassB
{
public void Display1()
{
Console.WriteLine(ClassA Display1″);
base.Display1();
}
}

ClassB:

class ClassB
{
public int x = 100;
public void Display1()
{
Console.WriteLine(ClassB Display1″);
}
public void Display2()
{
Console.WriteLine(ClassB Display2″);
}
}

Program.cs

class Program
    {
        static void Main(string[] args)
        {
            ClassA a = new ClassA();
            a.Display1();
            Console.ReadKey();
        }
    }

Output

ClassA Display1 
ClassB Display1
We see here first our ClassA Display1 method is called and then ClassB Display1 method.
Now if you want the best of both the classes , you may want to call the base classes (ClassBDisplay1 first and then yours or vice versa. To achieve this, C# gives you a free keyword, called base. The keyword base can be used in any of the derived class. It means call the method off the base class. Thus base.Display1 will call the methodDisplay1 fromClassB the base class
of ClassA as defined earlier.
 
Point to remember: A reserved keyword named “base” can be used in derived class to call the base class method.
What if we call Display2 method from base class, with an instance of derived class ClassA?
/// <summary>
   /// ClassB: acting as base class 
   /// </summary>
   class ClassB
    {
        public int x = 100;
        public void Display1()
        {
            Console.WriteLine("ClassB Display1");
        }
        public void Display2()
        {
            Console.WriteLine("ClassB Display2");
        }
    }

/// <summary>
/// ClassA: acting as derived class
/// </summary>
class ClassA : ClassB
{
public void Display1()
{
Console.WriteLine(ClassA Display1″);
base.Display2();
}
}

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
class Program
{
static void Main(string[] args)
{
ClassA a = new ClassA();
a.Display1();
Console.ReadKey();
}
}

Output

In the above code, we only made just a small change, base.Display1 was replaced by base.Display2. In this particular scenario, method Display2 from the class ClassB gets called. Base is usually a very general purpose. It lets us access members of the base class from the derived class as explained earlier. We cannot use base in ClassBas ClassB is not derived from any class as per our code. So it’s done that the base keyword can only be used in derived classes?
Let’s take another case:
/// <summary>
   /// ClassB: acting as base class 
   /// </summary>
   class ClassB
    {
        public int x = 100;
        public void Display1()
        {
            Console.WriteLine("ClassB Display1");
        }
    }

/// <summary>
/// ClassA: acting as derived class
/// </summary>
class ClassA : ClassB
{
public void Display2()
{
Console.WriteLine(ClassA Display2″);
}
}

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
class Program
{
static void Main(string[] args)
{
ClassB b = new ClassB();
b.Display2();
Console.ReadKey();
}
}

Output

Error: ‘InheritanceAndPolymorphism.ClassB‘ does not contain a definition for ‘Display2‘ and no extension method ‘Display2‘ accepting a first argument of type ‘InheritanceAndPolymorphism.ClassB‘ could be found (are you missing a using directive or an assembly reference?)
 
Point to remember: Inheritance does not work backwards.
So we got an error. Since we see, ClassA is derived from ClassB, i.e., ClassB is base class. Therefore, classClassAcan use all the members of class ClassB. Inheritance does not have backwards compatibility, whatever membersClassA contains do not permeate upwards toClassB. When we tried to access Display2 method of classA from the instance of class ClassB, it cannot give it to class ClassB and thus an error occurs.
 
Point to remember: Except constructors and destructors, a class inherits everything from its base class .
If a class ClassC is derived from class ClassB, which in turn has been derived from class ClassA, then ClassC will inherit all the members declared in ClassB and also of ClassA. This is called transitive concept in inheritance. A derived class may inherit all the members of the base class but it cannot remove members off that base class. A derived class can however hide members of the base class by creating methods by the same name. The original member/method of the base class remains unmodified and unaffected by whatever happens in the derived class. It remains unchanged in the base class, i.e., simply not visible in the derived class.
A class member could be of two types, i.e. either a static member that directly belongs to a class or an instance member that is accessed through instance of that class and belongs to that particular instance only. Instance member is accessible only through the object of the class and not directly by the class. The default member declared in the class are nonstatic, we just have to make them static by using static keyword.
All classes derive from a common base class named object. So Object is the mother of all classes.
If we do not derive any class from any other class, it’s the responsibility of C# to add :object by itself to the class definition. Object is the only class that is not derived from any other class. It is the ultimate base class for all the classes.
Suppose ClassA is derived from ClassB as in our case, but ClassB is not derived from any class,
public class ClassB
    {
    }

public class ClassA : ClassB
{
}

C# automatically adds :object to ClassB, i.e., the code at compile time becomes:
public class ClassB:object
    {
    }

public class ClassA : ClassB
{
}

But as per theory, we say ClassB is the direct base class of ClassA, so the classes of ClassA are ClassB and object.
Let’s go for another case:
public class ClassW : System.ValueType
    {
    }

public class ClassX : System.Enum
{
}

public class ClassY : System.Delegate
{
}

public class ClassZ : System.Array
{
}

Here we have defined four classes, each derive from a built in class in C#, let’s run the code.
We get so many compile time errors.

Errors

'InheritanceAndPolymorphism.ClassW' cannot derive from special class 'System.ValueType'
'InheritanceAndPolymorphism.ClassX' cannot derive from special class 'System.Enum'
'InheritanceAndPolymorphism.ClassY' cannot derive from special class 'System.Delegate'
'InheritanceAndPolymorphism.ClassZ' cannot derive from special class 'System.Array'
Don’t be scared.
Did you notice the word special class. Our classes defined cannot inherit from special built in classes in C#.
Point to remember: In inheritance in C#, custom classes cannot derive from special built in c# classes likeSystem.ValueTypeSystem.EnumSystem.DelegateSystem.Array, etc.
One more case,
public class ClassW
    {
    }

public class ClassX
{
}

public class ClassY : ClassW, ClassX
{
}

In the above mentioned case, we see three classes, ClassWClassX and ClassYClassY is derived from ClassWand ClassX. Now if we run the code, what would we get?
Compile time Error: Class ‘InheritanceAndPolymorphism.ClassY‘ cannot have multiple base classes: ‘InheritanceAndPolymorphism.ClassW‘ and ‘ClassX‘.
So one more Point to remember: A class can only be derived from one class in C#. C# does not support multiple inheritance by means of class*.
*Multiple inheritance in C# can be accomplished by the use of Interfaces, we are not discussing about interfaces in this article.
We are not allowed to derive from more than one class, thus every class can have only one base class.
Another case:
Suppose we try to write code as below:
public class ClassW:ClassY
    {
    }

public class ClassX:ClassW
{
}

public class ClassY : ClassX
{
}

Code is quite readable and simple, ClassW is derived from ClassYClassX is derived from ClassW, and ClassY in turn is derived from ClassX. So no problem of multiple inheritance, our code should build successfully. Let’s compile the code. What do we get? Again a compile time error.
Error: Circular base class dependency involving ‘InheritanceAndPolymorphism.ClassX‘ and ‘InheritanceAndPolymorphism.ClassW‘.
 
Point to remember: Circular dependency is not allowed in inheritance in C#. ClassX is derived from ClassW which was derived from ClassY and ClassY was again derived from ClassX, which caused circular dependency in three classes, that is logically impossible.

Equalizing the Instances/Objects

Let’s directly start with a real case:
ClassB:
public class ClassB
    {
        public int b = 100;
    }

ClassA:

public class ClassA
{
public int a = 100;
}

Program.cs

/// <summary>
    /// Program: used to execute the method.
    /// Contains Main method.
    /// </summary>
    public class Program
    {
        private static void Main(string[] args)
        {
            ClassB classB = new ClassB();
            ClassA classA = new ClassA();
            classA = classB;
            classB = classA;
        }
    }
We are here trying to equate two objects or two instances of two different classes. Let’s compile the code,
We get compile time error:
 
Error
Cannot implicitly convert type 'InheritanceAndPolymorphism.ClassB' to 'InheritanceAndPolymorphism.ClassA'

Cannot implicitly convert type ‘InheritanceAndPolymorphism.ClassA’ to ‘InheritanceAndPolymorphism.ClassB’

 
InheritanceAndPolymorphism is the namespace that I used for my console application, so there is no need to be scared of that word, just ignore it.
C# works on rules, it will never allow you to equate objects of different independent classes to each other. Therefore, we cannot equate an object classA of ClassA to classB of ClassB or vice versa. No matter the classes contain similar structure and their variables are initialized to similar integer value, even if we do.
public class ClassB
    {
        public int a = 100;
    }

public class ClassA
{
public int a = 100;
}

I just changed int b ofClassB to int a. In this case too, to equate an object is not allowed and not possible.
C# is also very particular if it comes with dealing with data types.
There is however one way to do this. By this way which we’ll discuss, one of the errors will disappear. The only time we are allowed to equate dissimilar data types is only when we derive from them? Check out the code mentioned below. Let’s discuss this in detail, when we create an object of ClassB by declaring new, we are creating two objects at one go, one that looks like ClassB and the other that looks like object, i.e., derived from Object class (i.e. ultimate base class). All classes in C# are finally derived from object. Since ClassA is derived from ClassB, when we declare newClassA, we are creating 3 objects, one that looks like ClassB, one that looks like ClassA and finally that looks likeobject class.
public class ClassB
    {
        public int b = 100;
    }

public class ClassA:ClassB
{
public int a = 100;
}

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
ClassA classA = new ClassA();
classA = classB;
classB = classA;
}
}

We just derived ClassA from ClassB, this is something we can do, we learned a lot about this in this article. Now compile the code, we get:
 
Error: Cannot implicitly convert type ‘InheritanceAndPolymorphism.ClassB‘ to ‘InheritanceAndPolymorphism.ClassA‘. An explicit conversion exists (are you missing a cast?)
Like I mentioned, C# is very particular about objects equating.
Thus when we write classA = classBclassA looks like ClassAClassB and object and as a looks like ClassB, there is a match at ClassB.Result? No error Smile | :) . Even though classB and classA have the same values, usingclassB we can only access the members of ClassB, even though had we used classA we could access ClassAalso. We have devalued the potency of classB. The error occurs at classA = classB, because the class ClassB is less/smaller than the class ClassA. The class ClassA has ClassB and more. We cannot have a larger class on the right and a smaller class on the left. classB only represents a ClassB whereas classA expects a ClassA which is aClassA andClassB.
 
Point to remember: We can only and only equate the dissimilar objects if they are derived from each other. We can equate an object of a base class to a derived class but not vice versa.
Another code snippet:
public class ClassB
    {
        public int b = 100;
    }

public class ClassA:ClassB
{
public int a = 100;
}

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
ClassA classA = new ClassA();
classB=classA;
classA = (ClassA)classB;
}
}

Although we violated a C# rule of equating objects, we did not get any compiler error because of the cast we did to the object. A() is called a cast. Within the brackets, the name of the class is put. A cast basically proves to be a great leveller. When we intend to write classA = classB, C# expects the right hand side of the equal to be a classA, i.e., a ClassA instance. But it finds classB, i.e., a ClassB instance. So when we apply the cast, we actually try to convert instance of ClassB to instance of ClassA. This approach satisfies the rules of C# on only equating similar objects type. Remember it is only for the duration of the line that classB becomes a ClassA and not a ClassB.
Now, if we remove ClassB as a base class to class ClassA as in the following code, and try to typecast classA toClassB object.
public class ClassB
    {
        public int b = 100;
    }

public class ClassA // Removed ClassB as base class
{
public int a = 100;
}

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
ClassA classA = new ClassA();
classB = (ClassB)classA;
classA = (ClassA)classB;
}
}

Output

Error
Cannot convert type 'InheritanceAndPolymorphism.ClassA' to 'InheritanceAndPolymorphism.ClassB'
Cannot convert type 'InheritanceAndPolymorphism.ClassB' to 'InheritanceAndPolymorphism.ClassA'
*’InheritanceAndPolymorphism’: Namespace I used in my application, so ignore that.
So we see that casting only works if one of the two classes is derived from one another. We cannot cast any two objects to each other.
One last example:
/// <summary>
    /// Program: used to execute the method.
    /// Contains Main method.
    /// </summary>
    public class Program
    {
        private static void Main(string[] args)
        {
            int integerA = 10;
            char characterB = 'A';
            integerA = characterB;
            characterB = integerA;
        }
    }
We run the code.

Output

Error: Cannot implicitly convert type ‘int‘ to ‘char‘. An explicit conversion exists (are you missing a cast?)
Point to remember: We cannot implicitly convert an int to char, but char can be converted to int.

Conclusion

In this part of our article series, we learned about inheritance. We took various scenarios and practical examples back to back to understand the concept deeply. In my next article, we’ll be discussing about run time polymorphism. Inheritance plays a very important role in run time polymorphism.
Let’s list down all our points to remember:
  1. No one can stop a derived class to have a method with the same name already declared in its base class.
  2. Derived classes get a first chance at execution, then the base class.
  3. A reserved keyword named “base” can be used in derived class to call the base class method.
  4. Inheritance does not work backwards.
  5. Except constructors and destructors, a class inherits everything from its base class.
  6. In inheritance in C#, custom classes cannot derive from special built in C# classes like System.ValueType,System.EnumSystem.DelegateSystem.Array, etc.
  7. A class can only be derived from one class in C#. C# does not support multiple inheritance by means of class.
  8. Circular dependency is not allowed in inheritance in C#. ClassX is derived from ClassW which was derived from ClassY and ClassY was again derived from ClassX, which caused circular dependency in three classes, that is logically impossible.
  9. We can only and only equate the dissimilar objects if they are derived from each other. We can equate an object of a base class to a derived class but not vice versa.
  10. We cannot implicitly convert an int to char, but char can be converted to int.
You can read about compile time polymorphism in my first article of the series. Keep coding and learning. .

Read more:

Other Series

My other series of articles:

For more informative articles visit my Blog.

For more technical articles you can reach out to CodeTeddy.

Diving in OOP (Part 1) : Polymorphism and Inheritance(Early Binding/Compile Time Polymorphism).


Introduction

I have been writing a lot about advanced topics like MVC, Entity Framework, Repository Patterns etc, my priority always remains to cover the topic as a whole, so that a reader does not have to search for missing links anywhere else. This article will cover almost every OOPS concept that a novice/beginner developer may hunt for, and not only beginners, the article’s purpose is to be helpful to experienced professionals who may need to brush-up on their concepts or who prepare for interviews.
I will take the topics in a manner that we cover them in a simple, straightforward way giving code snippets as example wherever needed. We’ll take C# as our programming language throughout our readings.
We’ll play with tricky questions and not go for enough theory. For theory you can refer MSDN.
Pre-requisites
Since this is the first part of the series, my readers should have basic knowledge of C# and should be aware of OOP concepts and terminology.
Note: Each and every code snippet written in this article is tried and tested.

OOPS

1. What is OOPS and what is advantage of OOP?

OOP stands for “Object-Oriented Programming.” Remember, it’s OOP not OOPS,’S’ may stand for system, synopsis, structure etc. It is a programming approach entirely based on objects, instead of just functions and procedures like in procedural languages. It is like a programming language model organized around objects rather than “actions” and data rather than logic. An “object” in an OOP language refers to a specific type, or “instance,” of a class. Each object has a structure exactly similar to other objects in a class, but can have individual properties/values. An object can also invoke methods, specific to that object
OOP makes it easier for developers to structure and organize software programs. Individual objects can be modified without affecting other aspects of the program therefore it is also easier to update and change programs written in object-oriented languages. Since the nature of software programs have grown larger over the years, OOP has made developing these large programs more manageable and readable.

2. What are OOP Concepts?

Following are OOP concepts explained in brief, we’ll take the topics in detail.
  1. Data Abstraction: Data Abstraction is a concept in which the internal and superfluous details of the implementation of a logic is hidden from an end user(who is using the program) .A user can use any of the data and method from the class without knowing about how this is created or what is the complexity behind it. In terms of a real world example, when we drive a bike and change the gears we don’t have to care about how internally its working, like how liver is pulled or how chain is set.
  2. Inheritance: Inheritance is most popular Concept in OOP’s .This provides a developer an advantage called reusability of code. Suppose a class is written having functions with specific logic, then we can derive that class into our newly created class and we don’t have to write the logic again for derived class functions, we can use them as it is.
  3. Data Encapsulation: Wrapping up of member data and member functions of a class in a single unit is called encapsulation. The visibility of the member functions,data members is set via access modifiers used in class.
  4. Polymorphism: Poly means many and morphism means many function The Concepts Introduces in the form of Many behaviours of an object.
  5. Message Communication: Message Communication means when an object passes the call to method of class for execution.
OK, we covered lots of theory, now it’s time for action. I hope that will be interesting. We’ll cover the topics in a series as follows,
  1. Diving in OOP (Day 1): Polymorphism and Inheritance(Early Binding/Compile Time Polymorphism)
  2. Diving in OOP (Day 2): Polymorphism and Inheritance (Inheritance)
  3. Diving in OOP (Day 3): Polymorphism and Inheritance (Dynamic Binding/Run Time Polymorphism)
  4. Diving in OOP (Day 4): Polymorphism and Inheritance (All about Abstarct classes in C#)
  5. Diving in OOP (Day 5): All about access modifiers in C# (Public/Private/Protected/Internal/Sealed/Constants/Readonly Fields)
  6. Diving in OOP (Day 6): Understanding Enum in C# (A Practical Approach)
  7. Diving into OOP (Day 7): Properties in C# (A Practical Approach)
  8. Diving into OOP (Day 8): Indexers in C# (A Practical Approach)
  9. Diving into OOP (Day 9): Understanding Events in C# (An Insight)

3. Polymorphism:

In this article we will cover almost all the scenarios of compile type polymorphism, the use of params keyword in detail, and case study or hands on to different possible combinations of the thoughts coming to our mind while coding.

Method Overloading or Early Binding or Compile Time Polymorphism

  1. Let’s create a simple console application named InheritanceAndPolymorphism, and add a class namedOverload.cs and add three methods named DisplayOverload having varied parameters as follows,

    Overload.cs

    public class Overload
        {
            public void DisplayOverload(int a){
                System.Console.WriteLine("DisplayOverload " + a);
            }
            public void DisplayOverload(string a){
                System.Console.WriteLine("DisplayOverload " + a);
            }
            public void DisplayOverload(string a, int b){
                System.Console.WriteLine("DisplayOverload " + a + b);
            }
        }

    In the main method in Program.cs file, add the following code,

    Program.cs

    class Program
        {
            static void Main(string[] args)
            {
                Overload overload = new Overload();
                overload.DisplayOverload(100);
                overload.DisplayOverload("method overloading");
                overload.DisplayOverload("method overloading", 100);
                Console.ReadKey();
            }
        }
Now when you run the application, the output is,

Output

DisplayOverload 100
DisplayOverload method overloading
DisplayOverload method overloading100
The class Overload contains three methods named DisplayOverload, they only differ in the datatype of the parameters they consist of. In C# we can have methods with the same name, but the datatypes of their parameters should differ. This feature of C# is called method overloading. Therefore, we need not to remember lots of method names if a method differs in behavior, only providing different parameters to the methods can call a method individually.
Point to remember: C# recognizes the method by its parameters and not by its name.
A signature signifies the full name of the method. So the name of a method or its signature is the original method name + the number and data types of its individual parameters.
If we run project using following code,
public void DisplayOverload() { }
     public int DisplayOverload(){ }
We certainly get a compile time error as,
Error: Type ‘InheritanceAndPolymorphism.Overload’ already defines a member called ‘DisplayOverload’ with the same parameter types
Here we had two functions who differ only in the data type of the value that they return, but we got a compile time error, therefore, another point to remember comes,
 
Point to remember: The return value/parameter type of a method is never the part of method signature if the names of the methods are same. So this is not polymorphism.
If we run the project using following code,
static void DisplayOverload(int a)  {   }
public void DisplayOverload(int a) {   }
public void DisplayOverload(string a){  }
We again get a compile time error,
Error: Type ‘InheritanceAndPolymorphism.Overload’ already defines a member called ‘DisplayOverload’ with the same parameter types
Can you differentiate with the modification done in the above code, we now have two DisplayOverload methods, that accept an int (integer). The only difference is that one method is marked static. Here the signature of the methods will be considered same as modifiers such as static are also not considered to be a part of method signature.
 
Point to remember: Modifiers such as static are not considered as part of method signature.
If we run the program as per following code, considering the method signature is different now,
private void DisplayOverload(int a) {   }

private void DisplayOverload(out int a)
{
a = 100;
}

private void DisplayOverload(ref int a) { }

We again get a compile time error,
Error: Cannot define overloaded method ‘DisplayOverload’ because it differs from another method only on ref and out
The signature of a method not only consists of the data type of the parameter but also the type/kind of parameter such as ref or out etc. Method DisplayOverload takes an int with different access modifiers i.e. out/ref etc, the signature on each is different.
 
Point to remember: The signature of a method consists of its name, number and types of its formal parameters. The return type of a function is not part of the signature. Two methods can not have the same signature and also non-members cannot have the same name as members.

4. Role of Params Parameter in Polymorphism

A method can be called by four different types of parameters.
  1. pass by value,
  2. Pass by reference,
  3. As an output parameter,
  4. Using parameter arrays.
As explained earlier the parameter modifier is never the part of method signature. Now let’s focus on Parameter Arrays.
A method declaration means creating a separate declaration space in memory. So anything created will be lost at the end of the method.
Running following code,
public void DisplayOverload(int a, string a)  {   }

public void Display(int a)
{
string a;
}

Results in compile time error,
 
Error1: The parameter name ‘a’ is a duplicate
Error2: A local variable named ‘a’ cannot be declared in this scope because it would give a different meaning to ‘a’, which is already used in a ‘parent or current’ scope to denote something else
 
Point to remember: Parameter names should be unique. And also we can not have a parameter name and a declared variable name in the same function as same.
In the case of pass by value, the value of the variable is passed and in the case of ref and out, the address of the reference is passed.
When we run the following code,

Overload.cs

public class Overload
    {
        private string name = "Akhil";

public void Display()
{
Display2(ref name, ref name);
System.Console.WriteLine(name);
}

private void Display2(ref string x, ref string y)
{
System.Console.WriteLine(name);
x = Akhil 1″;
System.Console.WriteLine(name);
y = Akhil 2″;
System.Console.WriteLine(name);
name = Akhil 3″;
}
}

Program.cs

class Program
    {
        static void Main(string[] args)
        {
            Overload overload = new Overload();
            overload.Display();
            Console.ReadKey();
        }
    }
We get out put as,

Output

Akhil
Akhil 1
Akhil 2
Akhil3

We are allowed to pass the same ref parameter as many times as we want. In the method Display the string name has a value of Akhil. Then by changing the string x to Akhil1, we are actually changing the string name to Akhil1 as name is passed by reference. Variables x and name refer to the same string in memory. Changing one changes the other. Again changing y also changes name variable as they refer to the same string anyways. Thus variables x, y and name refer to the same string in memory.
When we run the following code,

Overload.cs

public class Overload
    {
        public void Display()
        {
            DisplayOverload(100, "Akhil", "Mittal", "OOP");
            DisplayOverload(200, "Akhil");
            DisplayOverload(300);
        }

private void DisplayOverload(int a, params string[] parameterArray)
{
foreach (string str in parameterArray)
Console.WriteLine(str + + a);
}
}

Program.cs

class Program
    {
        static void Main(string[] args)
        {
            Overload overload = new Overload();
            overload.Display();
            Console.ReadKey();
        }
    }
We get output,

Output

Akhil 100
Mittal 100
OOP 100
Akhil 200
We will often get into a scenario where we would like to pass n number of parameters to a method. Since C# is very particular in parameter passing to methods, if we pass an int where a string is expected, it immediately breaks down. But C# provides a mechanism for passing n number of arguments to a method,
we can achieve it with the help ofparams keyword.
 
Point to remember: This params keyword can only be applied to the last argument of the method. So the n number of parameters can only be at the end.
In the case of method DisplayOverload, the first argument has to be an integer, the rest can be from zero to an infinite number of strings.
If we add a method like ,
private void DisplayOverload(int a, params string[] parameterArray, int b) {  }
We get a compile time error as,
 
Error: A parameter array must be the last parameter in a formal parameter list
Thus is is proved that params keyword will be the last parameter in a method, this is already stated in the latest point to remember.

Overload.cs

public class Overload
    {
        public void Display()
        {
            DisplayOverload(100, 200, 300);
            DisplayOverload(200, 100);
            DisplayOverload(200);
        }

private void DisplayOverload(int a, params int[] parameterArray)
{
foreach (var i in parameterArray)
Console.WriteLine(i + + a);
}

}

Program.cs

class Program
    {
        static void Main(string[] args)
        {
            Overload overload = new Overload();
            overload.Display();
            Console.ReadKey();
        }
    }
When we run the code we get,
200 100
300 100
100 200
Therefore,
 
Point to Remember: C# is very smart to recognize if the penultimate argument and the params have the same data type.
The first integer is stored in the variable a, the rest are made part of the array parameterArray.
private void DisplayOverload(int a, params string[][] parameterArray)  {     }

private void DisplayOverload(int a, params string[,] parameterArray) { }

For the above written code, we again get a compile time error and a new point to remember as well,
 
Error:The parameter array must be a single dimensional array
Point to remember: same as error above.
The data type of the params argument must be a single dimensional array. Therefore [ ][ ]
is allowed but not [,]. We also not allowed to combine the params keyword with ref or out.

Overload.cs

public class Overload
    {
        public void Display()
        {
            string[] names = {"Akhil", "Ekta", "Arsh"};
            DisplayOverload(3, names);
        }

private void DisplayOverload(int a, params string[] parameterArray)
{
foreach (var s in parameterArray)
Console.WriteLine(s + + a);
}

}

Program.cs

class Program
    {
        static void Main(string[] args)
        {
            Overload overload = new Overload();
            overload.Display();
            Console.ReadKey();
        }
    }

Output

Akhil 3
Ekta 3
Arsh 3
We are, therefore, allowed to pass a string array instead of individual strings as arguments. Here, names is a string array which has been initialized using the short form. Internally when we call the function DisplayOverload, C# converts the string array into individual strings.

Overload.cs

public class Overload
    {
        public void Display()
        {
           string [] names = {"Akhil","Arsh"};
           DisplayOverload(2, names, "Ekta");
        }

private void DisplayOverload(int a, params string[] parameterArray)
{
foreach (var str in parameterArray)
Console.WriteLine(str + + a);
}

}

Program.cs

class Program
    {
        static void Main(string[] args)
        {
            Overload overload = new Overload();
            overload.Display();
            Console.ReadKey();
        }
    }

Output

Error: The best overloaded method match for ‘InheritanceAndPolymorphism.Overload.DisplayOverload(int, params string[])’ has some invalid arguments
Error:Argument 2: cannot convert from ‘string[]’ to ‘string’
So, we got two errors. 
For the above mentioned code, C# does not permit mix and match. We assumed that the last string “Ekta” would be added to the array of strings names or convert names to individual strings and then add the string “Ekta” to it. Quite logical.
Internally before calling the function DisplayOverload, C# accumulates all the individual parameters and converts them into one big array for the params statement.

Overload.cs

public class Overload
    {
        public void Display()
        {
            int[] numbers = {10, 20, 30};
            DisplayOverload(40, numbers);
            Console.WriteLine(numbers[1]);
        }

private void DisplayOverload(int a, params int[] parameterArray)
{
parameterArray[1] = 1000;
}

}

Program.cs

class Program
    {
        static void Main(string[] args)
        {
            Overload overload = new Overload();
            overload.Display();
            Console.ReadKey();
        }
    }

Output

1000
We see that the output produced is the proof of concept. The member parameterArray[1] of array has an initial value of 20 and in the method DisplayOverload, we changed it to 1000. So the original value changes, this shows that the array is given to the method DisplayOverload, Hence proved.

Overload.cs

public class Overload
    {
        public void Display()
        {
            int number = 102;
            DisplayOverload(200, 1000, number, 200);
            Console.WriteLine(number);
        }

private void DisplayOverload(int a, params int[] parameterArray)
{
parameterArray[1] = 3000;
}

}

Program.cs

class Program
    {
        static void Main(string[] args)
        {
            Overload overload = new Overload();
            overload.Display();
            Console.ReadKey();
        }
    }

Output

102
In the above mentioned scenario C# creates an array containing 1000 102 and 200. We now change the second member of array to 3000 which has nothing to do with the variable number. As DisplayOverload has no knowledge of number, so how can DisplayOverload change the value of the int number? Therefore it remains the same.

Overload.cs

public class Overload
    {
        public void Display()
        {
            DisplayOverload(200);
            DisplayOverload(200, 300);
            DisplayOverload(200, 300, 500, 600);
        }

private void DisplayOverload(int x, int y)
{
Console.WriteLine(The two integers “ + x + + y);
}

private void DisplayOverload(params int[] parameterArray)
{
Console.WriteLine(parameterArray”);
}

}

Program.cs

class Program
    {
        static void Main(string[] args)
        {
            Overload overload = new Overload();
            overload.Display();
            Console.ReadKey();
        }
    }

Output

parameterArray
The two integers 200 300
parameterArray
Now we’ll talk about method overloading. C# is extremely talented though partial. It does not appreciate the paramsstatement and treats it as a stepchild. When we invoke DisplayOverload only with one integer, C# can only call theDisplayOverload that takes a params as a parameter as it matches only one int. An array can contain one member too. The fun is with the DisplayOverload that is called with two ints now. So here we have a dilemma. C# can call theparams DisplayOverload or DisplayOverload with the two ints. As discussed earlier, C# treats the params as a second class member and therefore chooses the DisplayOverload with two ints. When there are more than two ints like in the third method call, C# is void of choice but to grudgingly choose the DisplayOverload with the params. C# opts for the params as a last resort before flagging an error.
Now a bit tricky example, yet important,

Overload.cs

public class Overload
    {
        public static void Display(params object[] objectParamArray)
        {
            foreach (object obj in objectParamArray)
            {
                Console.Write(obj.GetType().FullName + " ");
            }
            Console.WriteLine();

}
}

Program.cs

class Program
    {
        static void Main(string[] args)
        {
            object[] objArray = { 100, "Akhil", 200.300 };
            object obj = objArray;
            Overload.Display(objArray);
            Overload.Display((object)objArray);
            Overload.Display(obj);
            Overload.Display((object[])obj);
            Console.ReadKey();

}
}

Output

System.Int32 System.String System.Double
System.Object[]
System.Object[]
System.Int32 System.String System.Double
In the first instance we are passing the method Display an array of object that looks like object. Since all the classes are derived from a common base class object, we can do that. The method Display gets an array of objectsobjectParamArray. In the foreach object class has a method named GetType that returns an object that looks like Type, which too has a method named FullName that returns the name of the type. Since three different types displayed. In the second method call of Display we are casting objArray to an object. Since there is no conversion available from converting an object to an object array i.e. object [ ], so only a one element object [ ] is created. It’s the same case in the third invocation and the last explicitly casts to an object array.
For proof of concept,

Overload.cs

public class Overload
    {
        public static void Display(params object[] objectParamArray)
        {
            Console.WriteLine(objectParamArray.GetType().FullName);
            Console.WriteLine(objectParamArray.Length);
            Console.WriteLine(objectParamArray[0]);

}
}

Program.cs

class Program
    {
        static void Main(string[] args)
        {
            object[] objArray = { 100, "Akhil", 200.300 };
            Overload.Display((object)objArray);
            Console.ReadKey();
        }
    }

Output

System.Object[]
1
System.Object[]

5. Conclusion

In this article of our Diving in OOP series we learnt about compile time polymorphism, it is also called early binding or method overloading. We catered most of the scenarios specific to polymorphism.We also learned about the use of powerful params keyword and its use in polymorphism.
To sum up lets list down all the point to remembers once more,
  1. C# recognizes the method by its parameters and not by its name.
  2. The return value/parameter type of a method is never the part of method signature if the names of the methods are same. So this is not polymorphism.
  3. Modifiers such as static are not considered as part of method signature.
  4. The signature of a method consists of its name, number and types of its formal parameters. The return type of a function is not part of the signature. Two methods can not have the same signature and also non-members cannot have the same name as members.
  5. Parameter names should be unique. And also we can not have a parameter name and a declared variable name in the same function as same.
  6. In case of pass by value, the value of the variable is passed and in the case of ref and out, the address of the reference is passed.
  7. This params keyword can only be applied to the last argument of the method.So the n number of parameters can only be at the end.
  8. C# is very smart to recognize if the penultimate argument and the params have the same data type.
  9. Parameter array must be a single dimensional array.
In upcoming articles we’ll cover topics in the same fashion.  Happy Coding.

Read more:

Other Series

My other series of articles:

For more informative articles visit my Blog.

For more technical articles you can reach out to CodeTeddy.