-1

I am writing a LINQ query. But, i am getting null object reference error for Model.StudentSummary.StudentDetails.

I put breakpoint on following foreach and when i mouse over Model.StudentSummary.StudentDetails i see StudentDetails is null.

I have initialized the whole model class than why it didn't initialize List<StudentDetails> in StudentSummary class?

foreach (Summary summary in Model.summaryData)
{
    Model.StudentSummary.StudentDetails.Add(new SafetyDetails
    {
        Name = summary.Name,
        ManTimeWorked = summary.TotalTime,
    });
}

Model.cs

public class Report : BaseReportModel
{
    public Report()
    {
      StudentSummary = new StudentSummary();
    }
    public StudentSummary StudentSummary { get; set; }
}

public class StudentSummary
{
    public string Name { get; set; }
    public List<StudentDetails> StudentDetails { get; set; }
}
TheKingPinMirza
  • 7,924
  • 6
  • 51
  • 81
  • 4
    Because reference types - like `List` - default to null. – stuartd Nov 23 '15 at 17:45
  • `StudentSummary`'s `StudentDetails` is not set. – Sergey Kalinichenko Nov 23 '15 at 17:45
  • 1
    A property that is a reference type will be `null` unless set to an existing object reference or allocated with `new` – crashmstr Nov 23 '15 at 17:45
  • But i initialized StudentSummary class than shouldn't it also initialize list? – TheKingPinMirza Nov 23 '15 at 17:47
  • 1
    @immirza *no*, it won't. Reference types are `null` until set with an existing object reference or allocated with `new`. You may want a `StudentSummary` constructor that sets `StudentDetails = new List();`. (just like your `Report` constructor allocates a `new StudentSummary();`). – crashmstr Nov 23 '15 at 17:48
  • 1
    No, initializing StudentSumary only initializes the reference to the list (to null). – Hutch Nov 23 '15 at 17:49

2 Answers2

3

Just because you initialized the object doesn't mean that all of its properties are initialized: each of those carries its default value until you change it, and the default for a List (or any class-type object) is null (more details in this post). You need to initialize the list.

You can inline this in your Report constructor like:

public class Report : BaseReportModel
{
    public Report()
    {
        StudentSummary = new StudentSummary
        {
            StudentDetails = new List<StudentDetails>()
        }
    }
    public StudentSummary StudentSummary { get; set; }
}

Another option is to initialize it in StudentSummary's constructor itself, which keeps the class in a nice state from the beginning without any additional work:

public class StudentSummary
{
    public StudentSummary()
    {
        StudentDetails = new List<StudentDetails>();
    }

    public string Name { get; set; }
    public List<StudentDetails> StudentDetails { get; set; }
}

This has a tradeoff: if you already have a List<StudentDetails> that you want to initialize it to, you needlessly create a new list - but if your regular use case is adding them as you do in the example code, it shouldn't be an issue.

Community
  • 1
  • 1
eouw0o83hf
  • 9,438
  • 5
  • 53
  • 75
1

If you're expecting StudentSummary.StudentDetails to be instantiated at the same time as StudentSummary you need to manually do it in the StudentSummary constructor, as you do with the StudentSummary in the Report constructor.

Andy Lamb
  • 2,151
  • 20
  • 22