HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Multiple functions to establish a fallback value for a property until not null

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
untilnullvalueestablishfallbackpropertyformultiplefunctionsnot

Problem

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();

    if (Head == null)
    {
        Head = this.GetComponentInChildren();

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


So I developed a loop:

System.Func[] fallbacks = new System.Func[]
{
    () => this.GetComponent(),
    () => this.GetComponentInChildren(),
    () => 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(this T obj, Func factory) where T : UnityEngine.Object
{
    return obj != null ? obj : factory();
}


With that extension method my code is now just

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

Solution

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

Head = GetComponent() ?? GetComponentInChildren() ?? 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(this T obj, Func factory) where T : class
{
    return obj != null ? obj : factory();
    // or
    // return obj == null ? factory() : obj;
}


then you can do:

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


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

Code Snippets

Head = GetComponent<Camera>() ?? GetComponentInChildren<Camera>() ?? Camera.main;
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;
}
Head = GetComponent<Camera>().IfNullThen(GetComponentInChildren<Camera>).IfNullThen(() => Camera.main);

Context

StackExchange Code Review Q#85020, answer score: 6

Revisions (0)

No revisions yet.