Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Member Variable: NullReferenceException

Discussion in 'Getting Started' started by tomihasa, Oct 2, 2016.

  1. tomihasa

    tomihasa

    Joined:
    Aug 2, 2016
    Posts:
    9
    Can I create my own class and have it as a member variable in a MonoBehaviour class? I come from a C++ and Java background, so I may have incorrect assumptions on how to use Unity classes at the moment.

    Error message:

    Code (CSharp):
    1. NullReferenceException: Object reference not set to an instance of an object
    2. UseCar.Start () (at Assets/Scenes/Scripts/UseCar.cs:9)
    Car:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Car {
    5.  
    6.     private int number;
    7.  
    8.     public Car() {
    9.         set( 1 );
    10.     }
    11.  
    12.     public Car( int smt ) {
    13.         set( smt );
    14.     }
    15.  
    16.     ~Car() {
    17.     }
    18.  
    19.     public int get() {
    20.         return number;
    21.     }
    22.  
    23.     public void set( int smt ) {
    24.         number = smt;
    25.     }
    26.  
    27.     public void increase() {
    28.         number++;
    29.     }
    30. }
    Class that tries to use Car as a member variable:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class UseCar : MonoBehaviour {
    5.  
    6.     public Car car;
    7.  
    8.     void Start() {
    9.         car.set( 1 );
    10.     }
    11.  
    12.     void Update() {
    13.         car.increase();
    14.         print( car.get() );
    15.     }
    16. }
    17.  
     
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,840
    Certainly! It's exactly the same as in Java (or as in C++, if you use some smart-pointer class instead of naked pointers).

    Such a reference will of course be null until you assign it some other value (again, just as in Java or C++). Note that this is true of classes but not structs; structs in C# are a little different (they are not nullable, so they get a default value).

    Yep. You never assigned a value to car, so of course when you try to use it, you get a null reference exception.

    Best,
    - Joe
     
  3. Kalladystine

    Kalladystine

    Joined:
    Jan 12, 2015
    Posts:
    227
    You need to call the constructor first in start.
    Code (CSharp):
    1.     void Start() {
    2.        car = new Car();
    3.         car.set( 1 );
    4.     }
    As a sidenote - unless you're dealing with external resources (system handles, sockets etc.) you probably will not need a destructor. C# manages the memory as long as you don't keep stray references hanging, but having a finalizer will also keep it active on the heap longer than it's needed.
    More details here - https://msdn.microsoft.com/en-us/library/66x5fx1b.aspx
     
    tomihasa likes this.
  4. tomihasa

    tomihasa

    Joined:
    Aug 2, 2016
    Posts:
    9
    Thanks, Kalladystine. For some reason I tried creating a new object outside the Start and Update methods like this:

    Errors:

    Code (CSharp):
    1. Assets/Scenes/Scripts/UseCar.cs(7,9): error CS1519: Unexpected symbol `=' in class, struct, or interface member declaration
    2. Assets/Scenes/Scripts/UseCar.cs(7,15): error CS0106: The modifier `new' is not valid for this item
    3. Assets/Scenes/Scripts/UseCar.cs(7,15): error CS1520: Class, struct, or interface method must have a return type
    4.  
    Initialization outside Start and Update methods:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class UseCar : MonoBehaviour {
    5.  
    6.     public Car car;
    7.     car = new Car();
    8.  
    9.     void Start() {
    10.         car.set( 1 );
    11.     }
    12.  
    13.     void Update() {
    14.         car.increase();
    15.         print( car.get() );
    16.     }
    17. }
    18.  
    I don't know what made me think that Start and Update are special methods where you can't initialize a member variable.
     
  5. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,840
    They're special only in the sense that they get looked up and invoked at the appropriate times by the Unity runtime. Here's an important run-down of which methods get called when.

    Your attempt to initialize your car field outside of any method failed because "car = new Car();" is a statement, and in C# (as in Java, right?) you can't have any statements outside of a method.

    However, there is one exception to that rule: you can have an initializer as part of a field declaration. So, this would have worked:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class UseCar : MonoBehaviour {
    5.  
    6.     public Car car = new Car();
    7.  
    8.     void Start() {
    9.         car.set( 1 );
    10.     }
    11.  
    12.     void Update() {
    13.         car.increase();
    14.         print( car.get() );
    15.     }
    16. }
    This is different because you're doing the initialization right there on the declaration line itself.
     
  6. Kalladystine

    Kalladystine

    Joined:
    Jan 12, 2015
    Posts:
    227
    Just as an interesting thing to know, the compiler will actually put that call in the constructor. Similar thing shown from IL perspective can be seen here (fair warning - Unity is stuck with a "little" older version of C#, but most things hold true).
    For anyone coming from C++, I'd recommend watching (or at least skimming) the whole playlist/C# topic on that channel, explanations are short and to the point, but with proof and reasoning (I'm kind of allergic to "because I say so" explanations, so that's a big plus for me).
     
    JoeStrout likes this.