1

I have run into an error that I can not seem to fix. After doing some research on Stack Overflow it seemed as though the null coalescing operator would be the solution to my problem, but it has not helped. Here is the code that gives the error:

List<OperationsReviewLevelResult> results = new List<OperationsReviewLevelResult>();
foreach (var approval in OperationsReviewers.ApprovalItems)
{
     var result = new OperationsReviewLevelResult();
     result.ApproverName = approval.Results.FirstOrDefault().Name ?? "";
     result.ReviewLevel = approval.Name;
     result.Comment = approval.Results.FirstOrDefault().Comments ?? "";
     results.Add(result);
}

When I run this code, I am getting:

Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.

Coming from the line result.ApproverName = approval.Results.FirstOrDefault().Name ?? "";. I added the null coalescing operator to check for null values, but this is not fixing my problem. The error is because there is no Results in approval so I assumed the FirstOrDefault linq method would return the default value, and when it realizes the default value has a null value for Name, it would use the null coalescing operator to return the "" empty string on the right side of the operator.

Please let me know if I am missing something as I can not seem to understand why I am getting this error even when adding the null coalescing operator.

Edit: As suggested in a comment, looking at this post helped me learn more into why I received this error. Although the questions are a bit different, I highly recommend reading the answer for getting a full understanding of my problem.

PhillyD
  • 181
  • 1
  • 18
  • 2
    Because you're accessing null.Name, try to use approval.Results.FirstOrDefault()?.Name – Nekeniehl Jan 29 '20 at 14:00
  • 3
    Probably `.FirstOrDefault()?.` since `FirstOrDefault()` can well return `null` – Dmitry Bychenko Jan 29 '20 at 14:00
  • 1
    You're only checking if `Name` is `null`, if `approval` is null, `approval.Results` is null, or if `approval.Results.FirstOrDefault()` returns null, you're still going to get that exception. You need to tack on a question mark before the dot of any sequence point that might be null. Assuming you have `approval.Results`, and only want to handle if `FirstOrDefault()` returns `null`, you can have `= approval.Results.FirstOrDefault()?.Name ?? "";` – Lasse V. Karlsen Jan 29 '20 at 14:01
  • 1
    If *all* the involved identifiers can be null you need the full `= approval?.Results?.FirstOrDefault()?.Name ?? "";` – Lasse V. Karlsen Jan 29 '20 at 14:02
  • if you have an expression of `a ?? b` it doesn't magically turn all possible null references inside `a` into evaluating `null`, it only checks if the end result of evaluating `a` ends up being `null`, then instead you will get `b`. In your case you have several places where you still dereference something, and they can all throw that exception. – Lasse V. Karlsen Jan 29 '20 at 14:04
  • Does this answer your question? [What is a NullReferenceException, and how do I fix it?](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – nilsK Jan 29 '20 at 14:53

2 Answers2

7

After each of your .FirstOrDefault() calls you need to add the ?. operator. Here's a full solution:

List<OperationsReviewLevelResult> results = new List<OperationsReviewLevelResult>();
foreach (var approval in OperationsReviewers.ApprovalItems)
{
     var result = new OperationsReviewLevelResult();
     result.ApproverName = approval.Results.FirstOrDefault()?.Name ?? "";
     result.ReviewLevel = approval.Name;
     result.Comment = approval.Results.FirstOrDefault()?.Comments ?? "";
     results.Add(result);
}

If it's possible other parts of the results could be null, you can go the full paranoid route

List<OperationsReviewLevelResult> results = new List<OperationsReviewLevelResult>();
foreach (var approval in OperationsReviewers.ApprovalItems)
{
     var result = new OperationsReviewLevelResult();
     result.ApproverName = approval?.Results?.FirstOrDefault()?.Name ?? "";
     result.ReviewLevel = approval?.Name;
     result.Comment = approval?.Results?.FirstOrDefault()?.Comments ?? "";
     results.Add(result);
}

And paranoid and LINQ-ified:

var results = OperationsReviewers.ApprovalItems
    .Select(approval => new OperationsReviewLevelResult
    {
        ApproverName = approval?.Results?.FirstOrDefault()?.Name ?? "",
        ReviewLevel = approval?.Name,
        Comment = approval?.Results?.FirstOrDefault()?.Comments ?? ""
    }
    .ToList();
Kit
  • 20,354
  • 4
  • 60
  • 103
7

The most probable cause is that FirstOrDefault() returns null (as a default value) and thus FirstOrDefault().Name throws exception. You can try null propagation with help of ?.

   foreach (var approval in OperationsReviewers.ApprovalItems)
     results.Add(new OperationsReviewLevelResult() {
       ApproverName = approval.Results.FirstOrDefault()?.Name ?? "",
       ReviewLevel  = approval.Name,
       Comment      = approval.Results.FirstOrDefault()?.Comments ?? "",
     });

So if approval.Results is empty and thus FirstOrDefault() returns null then FirstOrDefault()?.Name returns null which is finally turns into ""

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • Thank you! I looked more into null propagation and was able to solve my question with your answer :) – PhillyD Jan 29 '20 at 15:30