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