March 29 2020
Today I’m starting a new series of short posts about neat C# features that many Unity game developers are missing on. In this post, you will learn about the improved Unity C# out Parameters feature that is available since C# 7.0.
When programming your game, you’ll often run into the need of returning multiple values within from a function.
Traditionally speaking, you have several ways to return multiple values.
In C++ is very common to use pointers/references as a way to return modified or even new variables. This often comes with requiring strong naming conventions to make it clear the function will modify these variables, e.g:
int Raycast(const Vector3& Direction, const Vector3& Position, HitResult** OutHitResult);
Another approach is to create aggregating structures that contain all the data you want to return. This method is verbose, but having named variables increases code clarity, e.g:
struct RaycastHitResult
{
int NumberTotalHits;
Collider FirstTargetHit;
}
RaycastHitResult Raycast(const Vector3& Direction, const Vector3& Position);OutHitResult);
On top of this, some languages offer tuples. C# has great support for tuples as we’ll see in an upcoming post.
But as of today, I’ll show you a neat variation C# offers you to return multiple values: Unity C# out parameters.
C# lets you use the out keyword in function parameters to make the programmer aware those variables will be initialized and set within that function.
In other words: you pass the function a variable that the function will set for you.
You can have as many out parameters as you want, which makes them useful to return multiple parameters within a function.
They existed for a long time, but it turns out C# 7.0 improved the way you and I work with these Unity C# out parameters.
Let’s see how.
Till C# 7.0, you had to declare your variables before passing them to the function you’re invoking.
This often required an extra line per out variable you want to pass, such as:
ChatMessageType type;
ServerGameLoop.ClientInfo target;
var text = ParseMessage(from, message, out type, out target);
if (type == ChatMessageType.Whisper)
{
// ...
}
This specific Unity C# out parameter improvement allows us, game developers, to declare these out variables inline along the function invocation.
The scope of the inline-declared variables is exactly the same as it used to be when declaring them before the function call.
And you can declare these inline out parameters with an explicit type or by using automatic type inference (var).
This way, you can turn the previous example into:
Either this
var text = ParseMessage(from, message, out var type, out var target);
if (type == ChatMessageType.Whisper)
{
// ...
}
Or this
var text = ParseMessage(from, message, out ChatMessageType type, out ServerGameLoop.ClientInfo target);
if (type == ChatMessageType.Whisper)
{
// ...
}
Even though the Unity API barely uses C# out parameters, I certainly see many Unity projects using those in their code base. That’s why this post is relevant for many of you, Unity game developers.
Let’s see some examples.
Raycasting has many applications, such as for AI to detect line of sight.
In Unity, you cast rays through the Physics API.
Here’s the C# 7.0 transformation:
From:
RaycastHit raycastHit;
if (Physics.Raycast(cosmicRay, out raycastHit))
{
Debug.Log("Hit ya " + raycastHit.collider.name);
}
To:
if (Physics.Raycast(cosmicRay, out RaycastHit raycastHit))
{
Debug.Log("Hit ya " + raycastHit.collider.name);
}
Related: Avoid using Physics.RaycastAll, as this version allocates memory and is detrimental to performance. Use Physics.RaycastNonAlloc instead.
Sometimes you have to do conversions from string to other types, such as when reading from a configuration file or user input.
C# makes this easy with TryParse, which uses an out parameter to give you what you wanted. here, we can profit from the improved Unity C# out parameters:
From:
int hitpoints;
if (int.TryParse(hitpointsString, out hitpoints))
{
Debug.Log($"You're {hitpoints} hitpoints away from table flipping");
}
To:
if (int.TryParse(hitpointsString, out int hitpoints))
{
Debug.Log($"You're {hitpoints} hitpoints away from table flipping");
}
The pattern same applies to float, double, long, etc..
I love dictionaries.
C# dictionaries have the famous TryGetValue method, which can become quite verbose after using it so many times.
It gets old very quickly.
Suppose we have a dictionary that maps inventory slots to game objects representing items (I don’t say this is a good idea, eh):
int slotId = 1;
var inventory = new Dictionary<int, GameObject>();
We can then improve our coding style…
From:
GameObject item;
if (inventory.TryGetValue(slotId, out item))
{
Debug.Log($"Looted {item.name}");
}
To:
if (inventory.TryGetValue(slotId, out GameObject item))
{
Debug.Log($"Looted {item.name}");
}
This improved version of C# out parameters is a neat little addition to remove verbosity from your code.
Some people will like it, some won’t.
And that’s fine. Just choose one style and stick to it.
In the next post in the C# series, I’ll show you an additional way of returning multiple values with C# 7.0.
Till then, why don’t you have a look at how Unity Addressables will save you from development pain?
~Ruben