我如何提示 C# 8.0 可空引用系统使用反射初始化 属性

How can I hint the C# 8.0 nullable reference system that a property is initalized using reflection

当我尝试将 Entity Framework Core 与 C# 8.0 中新的可空引用类型一起使用时,我 运行 遇到了一个有趣的问题。

Entity Framework(各种风格)允许我声明我从未初始化的 DBSet 属性。例如:

    public class ApplicationDbContext : IdentityDbContext
      {
    #pragma warning disable nullable
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
          : base(options)
        { }
    #pragma warning restore nullable

        public DbSet<Probe> Probes { get; set; }
        public DbSet<ProbeUnitTest> ProbeUnitTests { get; set; }
    }

DbContext 构造函数反映类型并初始化所有 DbSet 属性,因此我知道构造函数结束时所有属性都将是非空的。如果我省略#pragma,我会得到预期的警告,因为我的代码没有初始化这些属性。

 Data\ApplicationDbContext.cs(10,12,10,32): warning CS8618: Non-nullable property 'Probes' is uninitialized.
 Data\ApplicationDbContext.cs(10,12,10,32): warning CS8618: Non-nullable property 'ProbeUnitTests' is uninitialized.

当我只想通知编译器 属性 不会为空时,关闭警告似乎是一种生硬的工具?

如果事实证明我可以像这样欺骗编译器:

     public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
      : base(options)
    {
      Probes = Probes;
      ProbeUnitTests = ProbeUnitTests;
    }

这段代码的优点是它非常狭窄 -- 它只适用于特定的 属性 的初始化,不会抑制其他警告。缺点是这是无意义的代码,因为将 属性 分配给自身实际上应该什么都不做。

是否有一个首选的习惯用法来通知编译器它只是不知道 属性 已经初始化?

每当您想告诉编译器 "shut up, I know what I'm doing" 可空引用类型时,请使用 ! 运算符。您可以像这样声明您的属性来解决您的问题:

public DbSet<Probe> Probes { get; set; } = null!;
public DbSet<ProbeUnitTest> ProbeUnitTests { get; set; } = null!;

Microsoft 有 2 条关于 DbContext and DbSet 上下文中可为空引用的建议

1

The common practice of having uninitialized DbSet properties on context types is also problematic, as the compiler will now emit warnings for them. This can be fixed as follows:

    // ...
    public DbSet<Customer> Customers => Set<Customer>();
    public DbSet<Order> Orders => Set<Order>();
    // ...

2

另一个是@dave-m :

Another strategy is to use non-nullable auto-properties, but to initialize them to null, using the null-forgiving operator (!) to silence the compiler warning.

public DbSet<Customer> Customers { get; set; } = null!;
public DbSet<Order> Orders { get; set; } = null!;

如果您使用的是 .NET 5,您现在可以使用 MemberNotNullAttribute 来指示哪些成员在方法 returns 之后不为 null。

public class ApplicationDbContext : IdentityDbContext
{
    [MemberNotNull(nameof(Probes))]
    [MemberNotNull(nameof(ProbeUnitTests))]
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
      : base(options)
    { }

    public DbSet<Probe> Probes { get; set; }
    public DbSet<ProbeUnitTest> ProbeUnitTests { get; set; }
}