N0xus
N0xus

Reputation: 2724

C# list property

I have a list I've set up as a property. I want to add to this list from another class but when I run my code tells me I have null reference. However, I can read from the list just fine. It is only when I add to the list does the error show.

What am I doing wrong?

Property Class

public List<string> ownedShips;

void Start()
{
    ownedShips = new List<string> ();

}

public List<string> Ships
{
    get {return ownedShips;}
    set {ownedShips = value;}
}

Adding to the list from another class:

    public int shipCost; 
public bool purchasedShip;
public string shipName = "test";
TESTPlayerAccount player;


// Use this for initialization
void Start () 
{
    player = new TESTPlayerAccount ();
    Debug.Log (player.Currency);
}


public void BuyShip()
{
    if(player.Currency >= shipCost)
    {
        player.Ships.Add(shipName);

    }


}

Upvotes: 1

Views: 223

Answers (5)

Kritner
Kritner

Reputation: 13765

You seem to be using functions named Start in place of constructors. If you have to have something initialized when a class instance is created, a constructor is the way to go, as it will be called automatically.

public class TESTPlayerAccount 
{

    private List<string> ownedShips;

    public TESTPlayerAccount()
    {
        ownedShips = new List<string> ();

    }

    public List<string> Ships
    {
        get {return ownedShips;}
        set {ownedShips = value;}
    }

}

Note that a constructor (public TESTPlayerAccount()) was added in place of your Start() function. The constructor is called automatically at object instantiation when instantiating the class as:

TESTPlayerAccount player = new TESTPlayerAccount();

Constructors can also have parameters. Consider the following constructor that could be added to TESTPlayerAccount in addition to the parameterless constructor that already exists (public TESTPlayerAccount()):

public TESTPlayerAccount(string shipToAddAtStart)
{
    ownedShips = new List<string> ();

    this.Ships.Add("The best ship evor!");
}

With both of these constructors, you have different behavior.

In the parameterless constructor public TESTPlayerAccount() your list is initialized and that's it.

In the second constructor public TESTPlayerAccount(string shipToAddAtStart) you can provide an initial element to add to the list. Granted you probably don't need the second constructor, just throwing it out there to show you can have more than one constructor for a class that takes different parameters and executes different behavior.

Upvotes: 1

HashPsi
HashPsi

Reputation: 1391

You need to initialize the field backing the property:

public List<string> ownedShips = new List<string>();

If the contract for the 'Player' class guarantees that 'Start' is called at instantiation, then initializing the backing field is not required. However, it would be good defensive practice to do so even if that's the case.

Upvotes: 2

bashis
bashis

Reputation: 1243

Judging by the comment, I assume you are using Unity.

If it's true, the Start() function is only called for classes that inherit from MonoBehaviour class.

For your custom classes that do not inherit from MonoBehaviour, change your Start() funtion to the default constructor like this:

TESTPlayerAccount:

public List<string> ownedShips;

public TESTPlayerAccount()
{
    ownedShips = new List<string> ();
}

public List<string> Ships
{
    get {return ownedShips;}
    set {ownedShips = value;}
}

Upvotes: 1

Luthervd
Luthervd

Reputation: 1406

You need to initialize your list. You should really do this in a constructor if you want the collection on the call to new. Also C# has auto properties that mean you only need to write:

Public List<string> MyList {get; set;}

Also you ideally want to expose your property as an interface. The .net generic collections gives you:

IEnumerable<T>
ICollection<T>
IList<T>

In your class you can instantiate any of these interfaces as a List but the exposed type is more flexible.

Upvotes: 1

walruz
walruz

Reputation: 1319

You need something like that, I think

class TESTPlayerAccount 
{
    private List<string> ownedShips;

    public TESTPlayerAccount ()
    {
        ownedShips = new List<string>();    
    }

    public List<string> Ships
    {
        get {return ownedShips;}
    }
}

Upvotes: 2

Related Questions