我如何提示 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; }
}
当我尝试将 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; }
}