Throughout my game development journey with Unity + C#, I have found the C# language extremely flexible and versatile. By utilizing the right techniques, one could eliminate lots of boiler plate and achieve remarkable expressiveness.
I talk about expressive code a lot in my posts, but if you need a refresher, expressive code is simply doing more stuff with less code. I would like to shed some light on two use cases today, both of which utilize generics to achieve their expressive nature.
An event system, observer patter, publish-subscribe .. etc, is a very basic design that is mostly needed in any type of software system. It helps you achieve decoupling between an event publisher and its subscribers.
So, we want to have a nice event system that satisfies the following conditions:
- Statically typed
- Clear usage
- Easy to define new events
Since C# has the
event data type, which allows you to define events and start utilizing the observer pattern, let’s evaluate that first:
This is a bit redundant. We have to define the
delegate, check for
null if we want to trigger the event, and the line isn’t very clear between who is the publisher, and who is the subscriber. Both perform a call on the event itself, after all..
The developer working with me took a slightly simpler approach using the
It gets super annoying after defining a few events, rewriting that null check and extra method each and every single time…
This also has a horrible side effect .. Multiple times, the game crashed because someone was triggering the
Action object directly, instead of going through the method!
The code above illustrates two valid ways to trigger the event, however, the second approach crashes the game if there aren’t any handlers, since it’s missing a
null check. This made me seek C# for some yoga lessons and introduce some versatile construct that can solve this issue.
I called the class
DKEvent, and this is how you can use it:
null checks, very clear distinction between publishing and subscribing, and best of all, it’s a single line of code to define new events! How can we achieve this beauty?
Simple enough, by using generics!
Things to note about the code above:
- You can redefine the same class name, but with different number of generic arguments, as many times as you like.
- We have finally encapsulated the
nullcheck, and we simply define new events using the code we saw earlier.
Jumping directly to the second use case, which is stored properties. Imagine you have a class that has properties which need to persisted to disk. Typically, writing such property requires lots of boilerplate code:
The above code assumes you have a nice generic persistence manager class which you can easily call to store and retrieve properties as needed. This code isn’t too bad, but we can do better.
Using the same approach demonstrated earlier, we can replace the code above with:
The code may look ugly, but it’s just a one liner. With a single line, we can define a new stored property, without the need to rewrite the calls to the persistence manager and whatnot. In order to use the new code, however, we have to use the designated accessors:
This is because of the way
StoredProperty is implemented:
The only reason I know so much about generics is because I’ve played around it a lot with Swift. In swift, you can achieve a hell lot more than what was presented here, thanks to protocol extensions and type inference.
This feels like a rushed post :( .. it probably is… I just really didn’t want one whole month to pass without posting anything!!