When Unity and Inheritance Collide
It is almost unavoidable to work with GameObject based Unity and not come across Unity Messages - although chances are you might not even know it.
What is a Unity Message?
Unity used to make extensive uses of messages, it is now really frowned upon because of the poor performance. However, one type of “message” that persists are the ones your MonoBehaviour receives during its lifetime, e.g. Awake(), Start(), etc. To be honest they are not always referred to as messages, so I shall just name them ‘life-cycle calls’.
Life-cycle calls vs. Inheritance
Normally life-cycle calls do not cause any major problems, as long as you know the order they run in then everything works well. However, there is a murky grey area, and that is when you use Inheritance.
For this example I have created a few very simple scripts;
They all just log when their respective Awake and Start calls are made. The exception is SpecializedLifeCycleEmpty, it does not implement any calls.
For this test I created prefabs, each one with its corresponding script attached.
With Unity running a scene I then instantiated each one of the prefabs, these are the results.
// Instantiate Simple
Simple Awake
Simple Start// Instantiate Specialized
Specialized Awake
Specialized Start// Instantiate SpecializedEmpty
Base Specialized Empty Awake
Base Specialized Empty Start
The above results are probably what you expect to see, but what happens if we change SpecializedEmpty to implement just Awake?
// Instantiate SpecializedEmpty V2
Specialized Empty Awake
Base Specialized Empty Start
This is a bit of a problem. The Awake on the specialized class has run but not on the base class.
At this point I should say thank you to Andy Dobson for pointing out my dumb than dumber mistake.
The better solution is to change the signature in the base class from a standard private function to protected virtual, this is still called by Unity but then allows for standard inheritance to take place.
Take away
By default the Unity Messages do not follow standard inheritance, on the most specialized class will receive the message. However, you CAN alter the signature of the functions to make them compatible with inheritance.