Page 1 of 5
Inheritance is a great idea but it is a powerful technique that can be misused. C# provides the tools to keep inheritance under control or to turn it off completely if you want to.
This is a Chapter of our ebook on C# - a work in progress.
Most C# programmers are well aware that it is an object-oriented language and one of the pillars of the object-oriented method is inheritance as a way of making software reuse easy. However the idea is a little more than just software reuse, as objects provide reuse without inheritance.
The class as software reuse
If you create a class then the software you have implemented is a template for as many instances of the class as you care to create. This is software reuse in action and you benefit from it whenever you use any class library – the .NET base class library for example. However software reuse can go beyond simply using what has been provided to extending what has been provided and this is the role of inheritance.
Even before object-oriented languages programmers were using crude forms of inheritance to extend existing software. Copy and paste inheritance relied on access to the source code so that a chunk of working code could be literally copied into a new location and modified.
The problem with this approach is that any changes to the original code were not automatically passed on to the copied code. This quickly made maintenance next to impossible. Inheritance automates copy and paste reuse so that chains of extended and customised objects can be created safe in the knowledge that any updates to their core workings earlier in the chain are automatically passed on to later derived classes.
Inheritance is a cornerstone of the object-oriented method but not everyone is of the opinion that it is a good idea. Some see it as a contrived and a dangerous approach to building software. The problem is that if you modify a base class how can you be sure that the change doesn't break the derived classes in ways that are complex and difficult to fix? This is also sometimes expressed by referring to the coupling between classes.
For a good design classes should be loosely coupled, i.e. have a low dependency on each other's working and clearly inheritance involves very tight coupling between the base and derived classes. However, the nature of this coupling is very clear and precise and not really in the same category as classes that just happen to use each other's internal workings.
As a result of these views inheritance is often treated with caution if not downright avoidance. Many programmers believe that inheritance is difficult to control and that there are better ways to work. Interface inheritance is one such method – where a class inherits an interface which the programmer then has to implement.
If this sounds a lot like copy and paste inheritance you wouldn't be far from the truth. The whole point of Interface inheritance is that it isn't inheritance at all – it stops the propagation of changes down a chain of derived classes. Each class that implements the interface has the same set of methods and this is useful, especially when writing generic methods, but there is still the problem of maintaining multiple implementations of each interface to contend with.
Similarly containment, where a class is extended by being wrapped in an outer class has its advantages, but brings with it duplication of code and a partial reinstatement of the inheritance chain. That is, if the contained class is changed then the containing class can break.
If you want to extend software and make use of what has already been written you have to accept the fact that change to the base code can result in the derived code not working. So basically the problem is in finding ways of controlling inheritance and the current situation is confused and difficult. There are some simple ideas such as dividing the workings of a class into external and internal and making sure that only the external details are available for use – the principle of encapsulation – but this doesn't specify what should be inherited. Are the internal workings of a class fair game for reuse in a derived class?
The best answer is - sometimes. There are cases where the internal workings are important enough to the functioning of the class that not allowing derived classes access to them would defeat the point of inheritance. There are also cases where an internal facility shouldn't be reused by inheritance – but it is very difficult to find convincing examples that aren't just poor design or coding. Even more draconian is the idea that inheritance should be prohibited completely – an easy option in C#. Finally after finding ways of disabling inheritance we have the idea of the extension method which was introduced in C# 3.0 to allow class reuse and extension without inheritance.
When reading about the practicalities of inheritance control you need to keep in mind that there are many strong opinions about how things should be done but very little theoretical or practical evidence that this is indeed the case.