【发布时间】:2020-01-24 23:03:01
【问题描述】:
我们如何将不可为空的引用类型与Options pattern结合使用?
假设我们有一个名为 MyOptions 的选项模型。
需要这些选项的服务将IOptions<MyOptions> options 注入到构造函数中。
在IServiceCollection 上配置选项,如下所示:
services
.AddOptions<MyOptions>()
.Configure(options =>
{
options.Name = "ABC";
});
现在,问题在于MyOptions的定义:
public sealed class MyOptions
{
public string Name { get; set; }
}
产生警告:
CS8618 不可为空的属性“名称”未初始化。考虑将属性声明为可为空。
- 我们不想让
Name可以为空,因为我们需要在任何地方进行传统的空检查(这与不可为空的引用类型的目的背道而驰) - 我们无法创建构造函数来强制使用不可为空的
name值创建MyOptions类,因为Configure方法为我们构造了选项实例 - 我们不能使用 null-forgiving 运算符 技巧 (
public string name { get; set; } = null!;),因为这样我们就不能确保设置了Name属性,我们最终会得到一个null在Name属性中,这不是预期的(在服务内)
还有其他我忘记考虑的选项吗?
【问题讨论】:
-
string.Empty是否适合您的用例?我假设您对填充值的检查是使用string.IsNullOrWhiteSpace。 -
您检查过 IValidateOptions
吗? docs.microsoft.com/en-us/dotnet/api/… -
你是对的,我们仍然需要验证空字符串(或其他约束)。我刚刚发现我们可以将额外的
.Validate()调用链接到可能满足我们需求的选项注册方法。谢谢。 -
是的,我同意。我认为他们试图与现有的“可空值类型”功能保持一致,但恕我直言,与拥有一个更准确地描述该功能实际功能的名称相比,这不是一个重要的目标。 :)
-
@huysentruitw 问题不是关于模式,而是关于它的初始化机制,这与任何反序列化器没有什么不同。配置有同样的问题——两种机制都使用基于属性的初始化,因此会产生可空性错误。 两个都必须使用基于构造函数的初始化来避免该问题。
标签: c# asp.net-core c#-8.0 nullable-reference-types