5
\$\begingroup\$

I have a property (called "Head") that can be set externally. When "Head" is not set, it uses Unity3D's MonoBehaviour functions to try to find the best value for "Head". I started with a nested if, but the nesting was starting to get out of hand.

if (Head == null)
{
    Head = this.GetComponent<Camera>();

    if (Head == null)
    {
        Head = this.GetComponentInChildren<Camera>();

        if (Head == null)
        {
            Head = Camera.main;
        }
    }
}

So I developed a loop:

System.Func<Camera>[] fallbacks = new System.Func<Camera>[]
{
    () => this.GetComponent<Camera>(),
    () => this.GetComponentInChildren<Camera>(),
    () => Camera.main,
};

foreach (var fallback in fallbacks)
{
    if (Head != null)
    {
        break;
    }
    Head = fallback();
}

Would this create too much lambda overhead? Do you think the lambdas even increases readability? Is there a more elegant way to handle multiple fallbacks?

Edit:

RobH helped me discover the Null coalescing doesn't work with Unity3D components. RobH's extension method workaround worked great with some tweaking. I had to enforce that comparison had to be done through UnityEngine.Object.

public static T IfNullThen<T>(this T obj, Func<T> factory) where T : UnityEngine.Object
{
    return obj != null ? obj : factory();
}

With that extension method my code is now just

Head = Head
    .IfNullThen(() => this.GetComponent<Camera>())
    .IfNullThen(() => this.GetComponentInChildren<Camera>())
    .IfNullThen(() => Camera.main);
\$\endgroup\$
6
\$\begingroup\$

This seems to be a textbook case for the null coalescing operator ??

Head = GetComponent<Camera>() ?? GetComponentInChildren<Camera>() ?? Camera.main;

You also (probably) don't need to prefix with this

Edit:

If the null coalescing operator doesn't work (which is a massive shame) why not create an extension method?

public static T IfNullThen<T>(this T obj, Func<T> factory) where T : class
{
    return obj != null ? obj : factory();
    // or
    // return obj == null ? factory() : obj;
}

then you can do:

Head = GetComponent<Camera>().IfNullThen(GetComponentInChildren<Camera>).IfNullThen(() => Camera.main);

Unfortunately I'm on my mac so I don't have a compiler but I think it should work :)

\$\endgroup\$
  • 1
    \$\begingroup\$ System namespace qualifier to System.Func<T> is probably also redundant ;) \$\endgroup\$ – Mathieu Guindon Mar 25 '15 at 21:14
  • \$\begingroup\$ @Mat'sMug I'm so used to ReSharper fixing that sort of thing that I don't look for them anymore! :) \$\endgroup\$ – RobH Mar 25 '15 at 21:18
  • \$\begingroup\$ This is brilliant and should of totally worked. I was racking my brain why it wasn't. Unity3D has issues with null coalesing. forum.unity3d.com/threads/… \$\endgroup\$ – ShawnFeatherly Mar 25 '15 at 21:28
  • \$\begingroup\$ @ShawnFeatherly - does my edit make sense/work? \$\endgroup\$ – RobH Mar 25 '15 at 21:39
  • \$\begingroup\$ @RobH, worked great and much more readable. Thanks! Had to do some tweaks. I updated above with what I had to change. \$\endgroup\$ – ShawnFeatherly Mar 25 '15 at 22:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.