1

I have some custom classes defined that include lists of other classes like so:

public class Unit
{
    public string Name { get; set; }
    public List<Group> Contains { get; set; }
}

public class Group
{
    public string Name { get; set; }
    public Type Type { get; set; }
    public int Number { get; set; }
}

public static Type basic_1 = new Type() { Name = "basic_1", Number = 1, Cost = 13 };

The basic idea is that you have a unit which contains a list of groups, each with a different type. The type contains specific properties while the classes that contain them are organizational in nature.

I then try to start building out these classes like so:

Unit unit1 = new Unit() { Name = "Unit 1" };
Group group1 = new Group() { Name = "Group 1", Number = 10, Type = basic_1 };
unit1.Contains.Add(group1);

But here I receive the error (on the Add method) "Object reference not set to an instance of an object." Looking at the locals in the debugger I can see that the Unit, Group and Type were all created successfully and the group1 contains all the Type values it's supposed to, but unit1.Contains is null.

What am I doing wrong? FYI I've never done something like this before so I don't even know if it's possible, but it seems to work fine up until this point.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
thanby
  • 323
  • 1
  • 6
  • 22
  • 1
    Almost all cases of `NullReferenceException` are the same. Please see "[What is a NullReferenceException in .NET?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-in-net)" for some hints. – John Saunders May 01 '14 at 20:57
  • If you don't want to change your class, just new up the list. unit1.Contains = new List(); – asunrey May 01 '14 at 21:05
  • I would advise against making a writable `Contains` property. A list exposed as a readonly property can still be modified from outside the class (as in you can add and remove stuff in it) and this will prevent outside code to set the instance to null or to another list. Oh and don't name it `Contains` either. – Crono May 01 '14 at 21:24

3 Answers3

13

Your List<Group> Contains never gets initialized, so when you try to access it, you get a null reference exception. Essentially all null reference exceptions are the same, you're trying to use an object that's null.

In this case, let's just add a default constructor to initialize the list for us.

public class Unit
{
    public string Name { get; set; }

    public List<Group> Contains { get; set; }

    public Unit()
    {
        Contains = new List<Group>();
    }
}

By the way, Contains is a terrible name for a list. Contains is usually a function call, as it's a verb. Usually better to use a noun for a collection, such as Groups.

public class Unit
{
    public string Name { get; set; }

    public List<Group> Groups { get; set; }

    public Unit()
    {
        Groups = new List<Group>();
    }
}
mason
  • 31,774
  • 10
  • 77
  • 121
  • Ah for some reason the `Contains` method never occurred to me, thanks for pointing that out! – thanby May 02 '14 at 12:15
  • @thanby I would advise against making your list property writable, though. It's unlikely you'd want that. – Crono May 02 '14 at 12:47
  • @Crono On the contrary, I make them writable all the time. It just depends on the situation and how the object is intended to be used. – mason May 02 '14 at 13:35
  • @mason these situations should be marginal IMHO, not your everyday use case. I can't think of a design where I'd want an object to act differently on having a null collection instead of an empty collection. – Crono May 02 '14 at 14:49
4

Your Contains list within User class never gets instantiated.

You may want to change your User class to this instead:

public class Unit
{
    public string Name { get; set; }

    List<Group> list = new List<Group>();

    public List<Group> Contains
    {
        get { return list; }
    }
}

As you can see the Contains property now only returns a list instance that can of course be modified but never reaffected. Likely, this is what you'll want.

Although this is a tad outside the scope of your question, I would suggest that you rename the Contains property to Groups instead.

Crono
  • 10,211
  • 6
  • 43
  • 75
  • Type or namespace name 'var' could not be found - Forgive my n00bishness but what am I missing to allow me to use that? It works fine in a method but not in the class. – thanby May 01 '14 at 21:00
  • You could accomplish this same thing without the need for a private field, by using a private set operator on the property. Simplifies the code. `public List Contains {get; private set;}` – mason May 02 '14 at 13:36
  • @mason but then you'd need a constructor to instantiate the list. :) – Crono May 02 '14 at 14:50
1

You have initialized the Unit But Unit.Contains Does not initialize. Before Adding objects to Contains list it must be initialized.

Unit unit1 = new Unit() { Name = "Unit 1" };
Group group1 = new Group() { Name = "Group 1", Number = 10, Type = basic_1 };
unit1.Contains = new List<Group>();
unit1.Contains.Add(group1);

Or

In your Unit class constructor you can initialize List here the code

public class Unit
{
public string Name { get; set; }
public List<Group> Contains { get; set; }
public Unit()
{
Contains = new List<Group>();
}
}

I would prefer the 2nd solution as it will make sure that whenever Unit is initialized Contains will be initialized automatically.

Muhammad Saifullah
  • 4,292
  • 1
  • 29
  • 59