取消引用 FirstOrDefault 上可能为空的引用

Dereference of a possibly null reference on FirstOrDefault

我浏览了各种相关问题,但似乎找不到可以帮助我解决这个问题的问题。

我使用 EF Core Power Tools 设置了我的 DbContext;一个特定的实体如下:

// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
#nullable disable
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;

namespace FIS2DataTables.Tables
{
    [Table("Settings", Schema = "static")]
    [Index(nameof(Setting), IsUnique = true)]
    public partial class Settings
    {
        [Key]
        [Column("id")]
        public int Id { get; set; }
        [Required]
        [Column("setting")]
        [StringLength(50)]
        public string Setting { get; set; }
        [Required]
        [Column("value")]
        [StringLength(200)]
        public string Value { get; set; }
        [Column("intValue")]
        public int? IntValue { get; set; }
        [Column("bitValue")]
        public bool? BitValue { get; set; }
    }
}

现在我有两个引用这个特定实体的不同文件。这是其中一个文件(已简化):

using FIS2DataTables.Context;
using FIS2DataTools.Interfaces;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace FIS2DataTools.Services
{
    public class SettingsService : ISettingsService
    {
        private readonly IConfiguration Configuration;
        private readonly IDbContextFactory<FIS2TableContext> ContextFactory;

        public SettingsService(IDbContextFactory<FIS2TableContext> contextFactory, IConfiguration configuration)
        {
            ContextFactory = contextFactory;
            Configuration = configuration;
        }

        private T GetConfigSetting<T>(string toFind)
        {

            return Configuration.GetValue<T>(toFind);
        }

        private string GetDbSetting(string toFind)
        {
            using (FIS2TableContext context = ContextFactory.CreateDbContext())
            {
                return context.Settings.FirstOrDefault(x => x.Setting == toFind).Value;
            }
        }

        private async Task<string> GetDbSettingAsync(string toFind)
        {
            using (FIS2TableContext context = ContextFactory.CreateDbContext())
            {
                return (await context.Settings.FirstOrDefaultAsync(x => x.Setting == toFind)).Value;
            }
        }

        public string GetDomainName()
        {
            return GetDbSetting("DomainName");
        }

        public string GetPhotosPath()
        {
            return GetDbSetting("PhotosPath");
        }

        public async Task<string> GetPhotosPathAsync()
        {
            return await GetDbSettingAsync("PhotosPath");
        }

        public string GetStoragePath()
        {
            return GetConfigSetting<string>("StoragePaths:Local");
        }
    }
}

有问题的方法是 GetDbSetting 及其异步方法。在这两种方法中,此块:context.Settings.FirstOrDefault(x => x.Setting == toFind) 标记为:

Dereference of a possibly null reference

我的研究基本上表明这只是编译器的表达方式:

This might, maybe, be null at some point... I'm not sure

但是...我在解决方案的其他地方有完全相同的代码(我正在将它从项目 A 迁移到 B),但在其他位置它没有标记它。

首先,我对它的不一致感到惊讶;但此外,我想知道避免这种情况的最佳行动方案是什么?

编辑:既然我已经问了这个问题;我已经意识到被标记的实例是我在一个单独的项目中引用它的实例 - 它不像将分析器打结那么简单?

供参考,另一个文件(未被标记的文件)如下:

using FIS2DataLibrary.Data.Interfaces;
using FIS2DataLibrary.Helpers;
using FIS2DataLibrary.Tables;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System.Linq;
using System.Threading.Tasks;

namespace FIS2DataLibrary.Data.Services
{
    public class SettingsService : ISettingsService
    {
        private readonly IConfiguration Configuration;
        private readonly IDbContextFactory<FIS2_TableContext> ContextFactory;

        public SettingsService(IDbContextFactory<FIS2_TableContext> contextFactory, IConfiguration configuration)
        {
            ContextFactory = contextFactory;
            Configuration = configuration;
        }

        private T GetConfigSetting<T>(string toFind)
        {
            return Configuration.GetValue<T>(toFind);
        }

        private string GetDbSetting(string toFind)
        {
            using (FIS2_TableContext context = ContextFactory.CreateDbContext())
            {
                return context.Settings.FirstOrDefault(x => x.Setting == toFind).Value;
            }
        }

        private async Task<string> GetDbSettingAsync(string toFind)
        {
            using (FIS2_TableContext context = ContextFactory.CreateDbContext())
            {
                return (await context.Settings.FirstOrDefaultAsync(x => x.Setting == toFind)).Value;
            }
        }

        public string GetDomainName()
        {
            return GetDbSetting("DomainName");
        }

        public async Task<MailServerConnectionSettings> GetMailServerConnectionSettingsAsync()
        {
            return new MailServerConnectionSettings(await GetDbSettingAsync("MailHost"), await GetDbSettingAsync("MailUser"), await GetDbSettingAsync("MailPass"));
        }

        public string GetPhotosPath()
        {
            return GetDbSetting("PhotosPath");
        }

        public async Task<string> GetPhotosPathAsync()
        {
            return await GetDbSettingAsync("PhotosPath");
        }

        public string GetStoragePath()
        {
            return GetConfigSetting<string>("StoragePaths:Local");
        }
    }
}

两者之间的唯一区别是未标记的那个与它的 DbContext 版本存在于同一个解决方案中;而被标记的版本引用了来自单独项目的 DbContext。

因为唯一的区别是代码驻留在不同的项目中 - 那么带有警告的代码应该在相应的 .csproj 中具有 nullable references types enabled. Check for Nullable xml 元素。

您可以禁用可为空的引用类型或(我认为更好)处理潜在的可空性(例如,如果您确定查询应该始终 return 某些东西,则通过 First“删除”它) .