Here's a fun little quibble I've run into whilst mucking about with learning to code. I've seen it trip up a few other people on UnityAnswers and there's a pretty simple solution, thus; TIME TO DUST OFF THE BLOG.
Polymorphism is an exceptionally powerful concept. It's also the reason I will - and always - recommend people script in C# rather than Boo or Unity's weird hybrid Not-Quite-Java. In my current case, I found a situation wherein I needed to use an Interface with Unity's GetComponent<T>() function; it relates to making a 'IWeapons' interface for... well, components designed as Weapons to be 'fired' (which in said game can do anything to launching a single projectile to starting up a grappling beam with which you smash spaceships into spaceships and presumably investigate what maniacal laughter sounds like from behind an oxygen mask). As these 'weapon' components would be performing a very wide range of tasks, I felt the typical inheritance tree model would be too constricting and that an interface would be best.
Except, of course, for the GetComponent<T>() function. Which can, as you might imagine, only search for and return Components, aka 'Objects that Derive From the MonoBehaviour Class', of which an interface is no guarantee.
The solution? It's actually hilariously simple. There is a way to implement interface-like behaviour whilst still assuring you a derived from a certain base class. Namely, it's the concept of the abstract class.
Firstly, lets review. The purpose of an interface is purely to provide an agreed public contract; namely, any other class working with something that implements a specific interface is guaranteed to hold the methods and properties defined within that interface. So for example:
public interface IWeapon {
void Fire();
void StartFiring();
void StopFiring();
}
IWeapon weapon = GetComponent<IWeapon>();
weapon.Fire();
And this is what interfaces allow you; it is a simple guarantee that any class that implements a given interface (and, most beautiful of all, a single class can implement more than one interface) will contain the functions the interface specifies. For instance, that IWeapon interface guarantees that any implementing class will have a public Fire() methods with zero arguments, returning void. Which is all anything interacting with a weapon component will need to know.
However, the catch rolls in here; all my weapon components also need to be components (classes deriving from MonoBehaviour that you can slap onto gameobjects from the inspector) and an interface does not guarantee this. It just declares what functions and properties will be publicly available. Thus, GetComponent<T>(), which can only search for and return MonoBehaviour objects, fails when it comes to searching for interfaces. If, as above, I wrote:
IWeapon weaponComponent = GetComponent<IWeapon>();
error CS0309: The type `IWeapon' must be convertible to `UnityEngine.Component' in order to use it as parameter `T' in the generic type or method `UnityEngine.Component.GetComponent<T>()'
Enter, the abstract class.
public abstract class AbstractWeapon : Monobehaviour, IWeapon {
public abstract void Fire();
public abstract void StartFiring();
public abstract void StopFiring();
}
Now, if I have my weapon components all derive from AbstractWeapon, we ensure they implement IWeapon and we ensure they are a derived class from Monobehaviour, which GetComponent<T>() can work with:
AbstractWeapon weaponComponent = GetComponent<AbstractWeapon>();
There is a downside of course; a class can implement any number of interfaces, but can only have one base class; it's still an inheritance tree and thus there will naturally be a 'split' involved somewhere. Fortunately Unity's component based design lets you side-step this a little bit (whilst there will be splits, there's nothing to say you can't just have two different components).
Obviously you can still have some behaviour and code defined in the above abstract class example (which will probably prove advantageous; ie providing protected helper functions derived classes can call on rather that waste time writing the same snippet of code multiple times) - something you would not be able to do with an interface - but in this case, with all the methods marked abstract, it provides exactly the same functionality as an interface with a pre-defined base class. Which is exactly what we want.