取消引用 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
“删除”它) .
我浏览了各种相关问题,但似乎找不到可以帮助我解决这个问题的问题。
我使用 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
“删除”它) .