Reputation: 2724
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
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
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
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
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
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