This article discusses one of those programming topics that may be confusing at first but seems obvious once you know it.

As you know, C# enables you to overload the same method in a class with different arguments.  But it’s also possible to overload a method with arguments that inherit from one another.

Consider this simple example of Base and Derived classes:

class Base { }
class Derived : Base { } 

Here we overload the Do method with a single object, Base and Derived argument.  In this example, Derived inherits from Base which inherits from object:

class Methods
{
    public void Do( object o ) { }
    public void Do( Base b ) { }
    public void Do( Derived d ) { }
}

Question #1: Which overload executes?

Quick quiz: if you pass a Derived object to the Do method, which overload will execute?  Answer: the overload with the most-derived arguments that match the object passed.

So in this example, if you pass a Derived object to the Do method, it will execute the Do( Derived d ) method.  If you pass a Base object to the Do method, it will execute the Do( Base b ) method.  And of course if you pass a different object altogether (such as DateTime) to the Do method, it will execute the Do( object o ) method.

Question #2: Does the overload selection occur at compile or run time?

The overload selected is based on the compile-time declaration of the argument being passed, not the run-time instance.  This is because the compiler chooses which method overload to execute at compile-time, and hence it has to rely on the declaration of the passed object.

So in this example, if you pass an argument to the Do method that’s declared at compile-time as a Derived object, it will execute the Do( Derived d ) method as you would expect.  But if you pass an argument that’s declared at compile-time as a Base object but currently references a Derived object, it will execute the Do( Base b ) method.

To be clear, if you declare a variable as a Base:

Base b2 = null;

It doesn’t matter if you later assign it to a Derived object:

b2 = new Derived();

It will still execute the Do( Base b ) overload, even though the variable references a Derived object.

Simple Console Program

Here is a simple console program that demonstrates this concept:

using System; 

namespace CSharp411
{
    class Program
    {
        static void Main( string[] args )
        {
            object o1 = new object();
            object o2 = new Base();
            object o3 = new Derived();
            Base b1 = new Base();
            Base b2 = new Derived();
            Derived d1 = new Derived();
            DateTime t1 = new DateTime(); 

            Methods methods = new Methods();
            methods.Do( o1 );
            methods.Do( o2 );
            methods.Do( o3 );
            methods.Do( b1 );
            methods.Do( b2 );
            methods.Do( d1 );
            methods.Do( t1 ); 

            Console.ReadLine();
        }
    }
    class Methods
    {
        public void Do( object o )
        {
            Write( "object", o );
        }
        public void Do( Base b )
        {
            Write( "Base", b );
        }
        public void Do( Derived d )
        {
            Write( "Derived", d );
        }
        private void Write( string method, object obj )
        {
            Console.WriteLine( "Do( {0} ) on {1}", method, obj.GetType().Name );
        }
    }
    class Base { }
    class Derived : Base { }
} 

Program Output

Here is the console program output:

Do( object ) on Object
Do( object ) on Base
Do( object ) on Derived
Do( Base ) on Base
Do( Base ) on Derived
Do( Derived ) on Derived
Do( object ) on DateTime