DEV Community

Cover image for Polymorphism in C#
William Olsen
William Olsen

Posted on

Polymorphism in C#

Polymorphism is a very important pillar of object-oriented programming, right up there with encapsulation and inheritance. Polymorphism in Greek meaning "many-shaped", this pillar allows for objects to take multiple forms. This sounds more complex than it actually is, so lets dive into some examples.

I have class A and class B. B inherits A. In Main(), this allows for some interesting behaviour:

class A { } 

class B : A { }

public class Program
{
    public static void Main(string[] args)
    {
        A a = new B(); //No error?!
    }
}
Enter fullscreen mode Exit fullscreen mode

How is there no error thrown? I am clearly trying to assign an incorrect type to a variable! Except I'm not. When B inherits A, it becomes a form of A, meaning it can be passed along as A when needed.

Let's look at some more examples:

using System;

public class Program
{
    public static void Main(string[] args)
    {
        DoSomething(new A());
        DoSomething(new B());
    }
    static void DoSomething(A obj)
    {
        Console.WriteLine($"Object Type: {obj.GetType()}");
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

Object Type: A
Object Type: B
Enter fullscreen mode Exit fullscreen mode

Another example:

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main(string[] args)
    {
        List<A> objs = new List<A>();
        objs.Add(new A());
        objs.Add(new B());
        foreach (A obj in objs)
        {
            Console.WriteLine($"Object Type: {obj.GetType()}");
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

Object Type: A
Object Type: B
Enter fullscreen mode Exit fullscreen mode

I know you all are on the edges of your seats, but let me inform you of another crazy use of polymorphism: overriding methods. "But isn't that just inheritance?" I hear you ask. And you would be technically correct. Like all pillars of object-oriented programming, inheritance and polymorphism work hand-in-hand to provide you with the best features.

Now the method overriding can be done with two amazing keywords: virtual and override. virtual is essentially the method/field raising its hand to be overridden in a form of the class. override is the teacher calling on the method/field to override it in a form of the class.

Let's see these keywords in action:

using System;

public class Program
{
    public static void Main(string[] args)
    {
        DoStuff(new A());
        DoStuff(new B());
    }
    static void DoStuff(A obj)
    {
        obj.DoSomething();
    }
}

class A
{
    public virtual void DoSomething()
    {
        Console.WriteLine("I did something in A's method!");
    }
}

class B : A
{
    public override void DoSomething()
    {
        Console.WriteLine("I did something in B's method!");
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

I did something in A's method!
I did something in B's method!
Enter fullscreen mode Exit fullscreen mode

Both objects were passed as type A, yet had different implementations of the same method!

It is time to introduce the sealed keyword. If using virtual is like raising your hand, then using sealed is equivalent to keeping your hand down. And unlike that one teacher who tries to engage the whole class, the C# compiler will simply not call on that method/field to be overriden in a form of the class.

Yet another high octane example with us introducing class C:

class A
{
    public virtual void DoSomething()
    {
        Console.WriteLine("I did something in A's method!");
    }
}

class B : A
{
    public sealed override void DoSomething()
    {
        Console.WriteLine("I did something in B's method!");
    }
}

class C : B
{
    public override void DoSomething()
    {
        Console.WriteLine("I did something in C's method!");
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

error CS0239: 'C.DoSomething()': cannot override inherited member 'B.DoSomething()'
Enter fullscreen mode Exit fullscreen mode

So we can see that sealed cuts off the chain of overriding methods.

I know at this point you are in a code-induced coma from the amazing keywords you just learned how to use, but let me sneak one last keyword in the pile. Continuing with the classroom analogy, the new keyword is similar to that one overly enthusiastic student raising their hand and blocking another student behind them. This results in the teacher calling on the student in front, rather than the student behind. And before you freak out, I was also very surprised that the new keyword has another use than initializing objects.

Note: When using a form of a class as that base class, any new methods/fields will not work in hiding the original ones.

Example:

using System;

public class Program
{
    public static void Main(string[] args)
    {
        DoStuff(new A());
        DoStuff(new B());
    }
    static void DoStuff(A obj)
    {
        obj.DoSomething();
    }
}

class A
{
    public void DoSomething()
    {
        Console.WriteLine("I did something in A's method!");
    }
}

class B : A
{
    public new void DoSomething()
    {
        Console.WriteLine("I did something in B's method!");
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

I did something in A's method!
I did something in A's method!
Enter fullscreen mode Exit fullscreen mode

The new keyword failed because of passing B as type A. (this is why override exists!) An example of new working:

using System;

public class Program
{
    public static void Main(string[] args)
    {
        new A().DoSomething();
        new B().DoSomething();
    }
}

class A
{
    public void DoSomething()
    {
        Console.WriteLine("I did something in A's method!");
    }
}

class B : A
{
    public new void DoSomething()
    {
        Console.WriteLine("I did something in B's method!");
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

I did something in A's method!
I did something in B's method!
Enter fullscreen mode Exit fullscreen mode

Now, this hurts me as much as it hurts you, but I need to introduce one last keyword. And I know I said that new would be the last, but this is what happens when you trust a C# developer! Anyways, the last crucial keyword that you need to know is base. The base keyword allows you to access the base class methods and fields from a form of it, while not having to create a whole new object. It is just as convenient as it sounds.

Example:

using System;

public class Program
{
    public static void Main(string[] args)
    {
        new B().DoSomething();
    }
}

class A
{
    public virtual void DoSomething()
    {
        Console.WriteLine("I did something in A's method!");
    }
}

class B : A
{
    public override void DoSomething()
    {
        Console.WriteLine("I did something in B's method!");
        base.DoSomething();
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

I did something in B's method!
I did something in A's method!
Enter fullscreen mode Exit fullscreen mode

If you want to learn about all of the possibilities of using polymorphism in C#, I would suggest further investigating this Microsoft article.

Thanks for reading!

(Cover image source)

Discussion (3)

Collapse
mreggo profile image
Matthew Harris

My brain has died

Collapse
polterguy profile image
Thomas Hansen

Great writeup - For the record, it took me 5 years to learn polymorphism, and an additional 5 years to understand why I should (always) never use it though ... ;)

Collapse
pixelatedlagg profile image
William Olsen Author

Thanks! It took me a few months to (kind-of) master polymorphism and all of its weird intricacies, but I am still learning all of the uses of this great language feature.