Search Unity

Is "Variable => GetComponent<MyComponent>();" Expensive?

Discussion in 'Scripting' started by Marc-Saubion, Aug 22, 2022.

  1. Marc-Saubion

    Marc-Saubion

    Joined:
    Jul 6, 2011
    Posts:
    655
    Hi everyone.

    I found out I can replace a variable to assign in the editor by => Getcomponent. For example, I have a script on a GameObject using a Light Component.

    Code (CSharp):
    1. public Light LightVariable;
    Usually, I would use this and assign my variable in the editor.


    Code (CSharp):
    1. public Light LightVariable => GetComponent<Light>();
    But if I used this, I don't have to and the variable isn't event displayed in the editor which is nicer and simple.

    It's working fine so far but before I'm overusing it, I'd love to know if there are serious caveats I should be aware of. If it's using the GetComponent everytime the variable is used for example.

    Anyone knows about this and could point to some documentation or share experience?

    Thanks.
     
  2. pixldev

    pixldev

    Joined:
    Nov 6, 2019
    Posts:
    15
    AFAIK GetComponent will be called every time you access the property. The usual approach is to assign the variable in Start or Awake or in the inspector.
     
    Marc-Saubion, Bunny83 and TheDevloper like this.
  3. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,637
    If I understand correctly, when you do this:

    public Light LightVariable => GetComponent<Light>();

    that will call GetComponent every time that you reference LightVariable. I wouldn't say "expensive" necessarily, but finding the component every time is going to take a certain amount of time that will eventually stack-up.

    On the other hand you can just type in this:

    public Light LightVariable = GetComponent<Light>();

    And it will simply call GetComponent once and store the result in LightVariable. So it's actually very easy to avoid the cost of calling GetComponent over and over. It's better not to call GetComponent every time unless you have some weird situation where components are added and removed unpredictably.

    Edit: by the way. if you just want to hide it in the editor, then make the variable private or use the [HideInInspector] attribute.
     
    Last edited: Aug 22, 2022
    Marc-Saubion and oscarAbraham like this.
  4. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    Just to add to what @kdgalla said, if you can't initialize your variable from the start, you could lazily initialize it. You still call
    GetComponent<Light>()
    inside LightVariable, but you cache the result to avoid calling it multiple times if possible.

    Code (CSharp):
    1.         private Light m_CachedLightVariable;
    2.  
    3.         public Light LightVariable
    4.         {
    5.             get
    6.             {
    7.                 if (m_CachedLightVariable == null)
    8.                     m_CachedLightVariable = GetComponent<Light>();
    9.                 return m_CachedLightVariable;
    10.             }
    11.         }
    I'd suggest using this when
    1. You can't initialize the variable in Start or Awake for some reason.
    2. Or when the component might be destroyed and added again in the middle of play mode.
    EDIT
    About the overhead of GetComponent. If you are not using it hundreds of times every frame, you won't notice a difference. But if you use it a lot, it's such a low hanging fruit to cache its value, that you'd be better off doing it. That time could help you at least a little if have performance issues latter.

    It's slower the more components there are in the GameObject. You should try putting components that are accessed more often in the top of the component's list. Also, you should consider using TryGetComponent instead of GetComponent, it's faster in the Editor when the component doesn't exist.
     
    Last edited: Aug 22, 2022
    Marc-Saubion likes this.
  5. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    This actually is not possible in a field initializer like this. You would need to do the GetComponent call in Awake() or Start().
     
    Marc-Saubion and oscarAbraham like this.
  6. Marc-Saubion

    Marc-Saubion

    Joined:
    Jul 6, 2011
    Posts:
    655
    That's what I usually do. I was really tired for not mentioning it.

    An alternative with public variables manually assigned is to have them set in Reset which is called when the script is added to the GameObject. Reset is pretty good for adding idiot proofing around a script like adding complementary components or warning game designers that something is wrong.
     
  7. Marc-Saubion

    Marc-Saubion

    Joined:
    Jul 6, 2011
    Posts:
    655
    Thanks a lot, these are all very interesting.