Programming Unity

Don’t use MonoBehaviour.Invoke – or how to properly invoke a method

According to the unity docs page,  there’s currently only one implementation of MonoBehaviour.Invoke:

So the only way to tell which method should be invoked is by it’s literal name. And this is a very, very bad idea!

If you want to write maintainable and readable code, you’ll have to clean up regularly. Fortunately IDEs help us a lot and renaming variables, methods, classes, namespaces and even files has become as easy as running your project. Even modern software development processes like test driven development (TDD) are designed to facilitate refactoring. With TDD you’ll always know if you just broke something so you can refactor the heart out of your code.

However, if you use a string to invoke a method by it’s name, most IDE’s won’t touch the string if you refactor a method name. And your code might look like this:

The Method  OldName does not exist any more but the code will actually compile! In the best case your code crashes immediately after starting your program or tests. In the worst case, your tests don’t recognize the error and the program doesn’t crash for quite a wile because you execute that last line only in rare cases.

Even if your tests manage to find the bug, it’s maybe only your slow system test that finds it. And this is typically hours or days after you broke the code by refactoring a method. But even if it’s a fast unit test, it will still take you a minute to read the error and understand that you’ll have to change that string to “RefactoredName”.

One way to fix this would be to generate the  methodName parameter of  MonoBehaviour.Invoke with something like  nameof :

So whenever you refactor the name of the method that you want to invoke,  MonoBehaviour.Invoke  will be called with the proper parameters. However  nameof only appeared in C# 6.0 and many people still use mono 3.5 which does not support this.

An alternative could be to overload MonoBehaviour.Invoke so that it does not take a string but a delegate. So calling the overloaded version would look like this:

Fortunately, we don’t need to have access to the Unity code to create this overloaded Invoke method. Instead we can use an Extension Method:

Please note that this way you can call Invoke from any MonoBehaviour object, but you’ll have to call it by using the this keyword even if you’re already in an instance method of that object:

So now we have to implement our own Invoke method meaning we have to call the delegate after delay seconds. This can be easily done using a coroutine: