没有可空警告无法安全检测空值

Unable to safely detect null value without nullable warnings

我不太理解以下可为空的警告。

如您所见,我有一个表达式的一部分,其中 sheet 不为空,但 sheet.Id 可能为空。但是为什么我用sheet.Id.HasValue查不到呢?

我也试过 sheet.Id != null,但这给了我一个不同的警告。

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

如何安全地确定 sheet.Id 是否不为空?

更新

这个版本实际上是在没有警告的情况下编译的。但是我仍然不明白为什么其他版本给我警告。

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;
}

你可以合并

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

转换为一个等价的表达式:

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

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

我不确定为什么编译器不够聪明,无法意识到在某些表达式中,某些字段不再为空。

顺便说一句,根据您想要深入到可空链接兔子洞的多远,您可以重写图像中的代码,使其看起来像这样:

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;
}

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();
}