Jonathan Wood
Jonathan Wood

Reputation: 67193

Unable to safely detect null value without nullable warnings

I don't quite understand the following nullable warning.

As you can see, I have part of an expression where sheet is not null, but sheet.Id may be. But why can't I used sheet.Id.HasValue to find out?

enter image description here

enter image description here

I also tried sheet.Id != null, but that gives me a different warning.

Warning CS8625 Cannot convert null literal to non-nullable reference type.

How can I safely determine if sheet.Id is not null?

Update

This version actually compiles without warning. But I still don't understand why the other versions give me warnings.

public Worksheet? GetFirstWorksheet()
{
    WorkbookPart? workbookPart = Document.WorkbookPart;
    Workbook? workbook = workbookPart?.Workbook;
    if (workbook != null)
    {
        Sheets? sheets = workbook.GetFirstChild<Sheets>();
        Sheet? sheet = sheets?.Elements<Sheet>()
            .FirstOrDefault();
        if (sheet != null && sheet.Id?.Value != null)
            return ((WorksheetPart)workbookPart!.GetPartById(sheet.Id!)).Worksheet;
    }
    return null;
}

Upvotes: 0

Views: 247

Answers (1)

idz
idz

Reputation: 12988

You can combine

        if (sheet != null && sheet.Id?.Value != null)
            return ((WorksheetPart)workbookPart!.GetPartById(sheet.Id!)).Worksheet;

into a single equivalent expression:

         if (sheet?.Id?.HasValue == true)
            return ((WorksheetPart)workbookPart!.GetPartById(sheet.Id!)).Worksheet;

or

         if (sheet?.Id?.Value != null)
            return ((WorksheetPart)workbookPart!.GetPartById(sheet.Id!)).Worksheet;

I am not sure why the compiler is not smart enough to realize that the in some terms of your expression some of the fields could no longer be null.

By the way, depending on how far down the nullable chaining rabbit hole you want to go, you could rewrite the code from the images to look look something like this:

Worksheet? GetWorksheet(string name)
{
    WorkbookPart? workbookPart = Document.WorkbookPart;
    Worksheet? sheet = workbookPart?.Workbook
        .GetFirstChild<Sheets>()?.Elements<Sheet>()
        .Where(s => string.Compare(s.Name, name, true) == 0 && s.Id?.HasValue == true)
        .Select(s => ((WorksheetPart) workbookPart!.GetPartById(s.Id!)).Worksheet)
        .FirstOrDefault();
    return sheet;
}

or

Worksheet? GetWorksheet(string name)
{
    WorkbookPart? workbookPart = Document.WorkbookPart;
    return workbookPart?.Workbook
        .GetFirstChild<Sheets>()?.Elements<Sheet>()
        .Where(s => string.Compare(s.Name, name, true) == 0 && s.Id?.HasValue == true)
        .Select(s => ((WorksheetPart) workbookPart!.GetPartById(s.Id!)).Worksheet)
        .FirstOrDefault();
}

Upvotes: 2

Related Questions