Easier null checking in Unity?
I was reading a fellow developers plight with having to add so many null checks in their code when it made me wonder if it was possible to make life a bit easier with .net extensions.
Consider this typical bit of code
What can be done about it?
Well obviously my first suggestion would be to use TryGetComponent but whilst that does save a line, you still end with a lot of scoped LogError lines...Dirty.
.net Extension Method
What about something like this;
The above is extending Component with an new overload of GetComponent<T> that includes an error message. Problem solved? Well, yes and a couple of no’s.
When you change the original code it doesn’t work
var fakeComponent = GetComponent<SphereCollider>("Oh no, I need this fake component");
and the why is sort of weird (to me). The compiler doesn’t find the extension. You have to explicitly use good .net standards — ah now I know why you should code properly ;)
var fakeComponent = this.GetComponent<SphereCollider>("Oh no, I need this fake component");
Spot the difference? Whenever you use a call to a method on yourself you’re supposed to be clear by using “this.” Now the extension springs to life.
Yay so we’ve gone from;
So much tidier, yay for us, job done?
Problem 1. Error in the wrong place
When you use this code the Unity Console will spit out the debug.LogError but it will be in the extension method and not the calling method. It’s not a massive problem but it’s one to be aware of.
E.g. if my script called SeatShuffle uses the above code then the error message looks like this;
SeatShuffle:Start () (at Assets/CBC/Scripts/Player/SeatShuffle.cs:31)
The hyperlinks to both methods are there so it’s not too bad, but it’s not ideal.
Problem 2. Repeated error messages
Okay, now I’m getting a little crazy. But realistically all the error messages are pretty much going to be the same. “Null found, was expecting X”. Could we avoid that too?
CallerMemberName and/or default message
One of this less used .net attributes that can come in handy. Let’s change our call to just this;
var fakeComponent = this.GetComponent<SphereCollider>();
and add to our extension
In the above example if there wasn’t a sphere collider then we’d see;
“Start: Was expecting SphereCollider in SeatShuffle”
That’s pretty good, and if we really wanted to use our own message we can supply the default message too. Except…it doesn’t work.
The problem with the default param is that it is optional for the signature. Which means the compiler cannot know if our GetComponent call is supposed to use the extension or the original good ole GetComponent code. So we either always supply at least a constant string for the message and lose the CallerMemberName or we change the name of the method, classically in APIs that would mean adding a “Ext” suffix e.g.
public static T GetComponentExt<T>(this Component component ...
TBH I don’t like that approach I’d rather stick with being forced to use at least some additional message. So we end up with the extension;
and the call looking like
You can get/contribute to the final code at GitHub