0
  • I need to cache a great number of components at startup (and I cannot reference them in the monobehaviour directly)
  • I can't be sure when they will be requested (so I cannot cache them in Awake, because they could be requested from an Awake of another Monobehaviour)

My starting solution was to use a public get property, that was the pattern I'm more familiar with. But now I'm trying Lazy initialization (that is more readable).

Getting Components As Property

    // --------------- COMPONENT AS PROPERTY --------------- //
    private ComponentRequired _componentAsProperty;
    private ComponentRequired _ComponentAsProperty
    {
        get
        {
            if (_componentAsProperty == null) 
                _componentAsProperty = GetComponentInChildren<ComponentRequired>(true);
            return _componentAsProperty;
        }
    }

Retrieving Component As Lazy

    // --------------- COMPONENT AS LAZY --------------- //
    private Lazy<ComponentRequired> _componentAsLazy 
                => new Lazy<ComponentRequired>(GetComponentInChildren<ComponentRequired>(true));

I also read Cached property vs Lazy<T> (that was related to instantiation) and the same answer might apply to lazy retriaval of components.

Performance wise I did not find a great difference at the moment on the profiler, but I want to ask to make sure of any possible drawbacks with unity and components (especially for mobile platforms).

Jack Mariani
  • 2,040
  • 1
  • 12
  • 23

2 Answers2

0

For Unity it is better to avoid the Lazy implementation, because it can move out of the main thread (and GetComponent cannot be used outside of the main thread).

At this version of unity 2019.1.7, it's much safer to use properties to cache any component.

Jack Mariani
  • 2,040
  • 1
  • 12
  • 23
0

As an additional note to the answer, the cached property with a null check does not save much performance, because the Unity engine will have to access the C++ object to check if the GameObject was destroyed. You can gain a significant performance boost by introducing a bool flag instead.

private ComponentRequired _componentAsProperty;
private bool _componentInitialized;
private ComponentRequired _ComponentAsProperty
{
    get
    {
        if(_componentInitialized) return _componentAsProperty;
        _componentAsProperty = GetComponentInChildren<ComponentRequired>(true);
        _componentInitialized = true;
        return _componentAsProperty;
    }
}

This is especially relevant when the component might not exist and _componentAsProperty stays null. If, of course, these components are created later, this does not work. In that case, the child component could use GetComponentInParent to register during Awake().

Also note that if the gameObject was destroyed after the component was cached, this approach can still return a non-null C# object. The caller will have to implement a null-check to be sure the gameObject still exists.