Evil Code #007: Overloads

Time to do a bit of Evil Code again. Let’s look into following set of classes first.

public class BaseParameter { }
public class DerievedParameter :BaseParameter { }

public class BaseClass
{
   public void Foo(DerievedParameter param) => Console.WriteLine($"Inside {nameof(BaseClass)}");
}

public class DerievedClass : BaseClass
{
   public void Foo(BaseParameter param) => Console.WriteLine($"Inside {nameof(DerievedClass)}");
}

The client code looks like following.

var instance = new DerievedClass();
instance.Foo(new DerievedParameter());
instance.Foo(new BaseParameter());

What could be output of the above ? There might be tendency that the one might be inclined to think about an output that resembles following.

Inside BaseClass
Inside DerievedClass

But interestingly that is not quite right. The overload rules ensures that when there is a probable method in the most derieved compile type, the derieved method is chosen, even if there is a better choice in base class. The output of the code would be as following.

Inside DerievedClass
Inside DerievedClass

This is one of the reasons why overloading of base class methods are not recommended.

Let’s take a step further and introduce IEnumerable as method parameters. That’s when things get even more interesting.


public class BaseClass
{
  public void Foo(DerievedParameter param) => Console.WriteLine($"Inside {nameof(BaseClass)}");
  public void Bar(IEnumerable<DerievedParameter> paramList) => Console.WriteLine($"Inside {nameof(BaseClass)}");
}

public class DerievedClass : BaseClass
{
  public void Foo(BaseParameter param) => Console.WriteLine($"Inside {nameof(DerievedClass)}");
  public void Bar(IEnumerable<BaseParameter> paramList) => Console.WriteLine($"Inside {nameof(DerievedClass)}");
}
 instance.Bar(new List<DerievedParameter> { new DerievedParameter(), new DerievedParameter() });
instance.Bar(new List<BaseParameter> { new BaseParameter(), new BaseParameter() });

What could be the output of above ? As per our earlier knowledge, the output would be

Inside DerievedClass
Inside DerievedClass

Well, the actual answer is slightly more complicated. If you are running the code in a framework above 4.0, then you are bang on target. But, if the target framework is lesser, you are in for a surprise.

Inside BaseClass
Inside DerievedClass

The reason for the above scenario is that post 4.0, C# generic interfaces support covariance and contravariance, which wasn’t the case for frameworks prior to that. This results in above scenario.

Happy Coding

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s