可空引用类型和选项模式 [英] Nullable Reference Types and the Options Pattern

查看:160
本文介绍了可空引用类型和选项模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们如何将不可为空的引用类型假设我们有一个名为MyOptions的期权模型.

Let's say we have an options model named MyOptions.

需要这些选项的服务正在将IOptions<MyOptions> options注入到构造函数中.

The services requiring those options are getting IOptions<MyOptions> options injected into the constructor.

像这样在IServiceCollection上配置选项:

services
    .AddOptions<MyOptions>()
    .Configure(options =>
    {
        options.Name = "ABC";
    });

现在,问题出在MyOptions的定义中:

Now, the problem is in the definition of MyOptions:

public sealed class MyOptions
{
    public string Name { get; set; }
}

会生成警告:

CS8618不可初始化的属性名称"未初始化.考虑将属性声明为可为空.

CS8618 Non-nullable property 'Name' is uninitialized. Consider declaring the property as nullable.

  1. 我们不想使Name为可空值,因为我们需要将传统的空值检查置于各处(这与不可空值引用类型的目的相反)
  2. 由于Configure方法为我们构造了options实例,因此我们无法创建构造函数来强制使用不可为空的name值创建的MyOptions
  3. 我们不能使用 null-togiving运算符技巧(public string name { get; set; } = null!;),因为这样我们就不能确保设置了Name属性,而最终只能得到nullName属性中(在服务内部)不会出现的情况
  1. We don't want to make Name nullable as then we need to place traditional null checks everywhere (which is against the purpose of non-nullable reference types)
  2. We can't create a constructor to enforce the MyOptions class to be created with a non-nullable name value as the Configure method construct the options instance for us
  3. We can't use the null-forgiving operator trick (public string name { get; set; } = null!;) as then we can't ensure the Name property is set and we can end up with a null in the Name property where this would not be expected (inside the services)

我忘了考虑其他选择吗?

Any other option I forgot to consider?

推荐答案

似乎您在这里有两个可能的选择.第一个方法是使用空字符串(而不是null值)初始化Options属性,以避免null检查

It seems, that you have two possible options here. First one is to initialize an Options properties using empty string (instead of null value) to avoid null checks

public sealed class MyOptions
{
    public string Name { get; set; } = "";
}

第二个是将所有属性设置为可为空的属性,并使用

Second one is to make all of the properties a nullable ones and decorate them using DisallowNull precondition and NotNull postcondition.

DisallowNull表示可为空的输入参数永远不应为null,NotNull-可为空的返回值永远不会为null. 但是,这些属性仅影响对带有注释的成员的调用者的可空分析.因此,您表示尽管声明可以为空,但您的媒体资源永远不会返回null或被设置为null

DisallowNull means that nullable input argument should never be null, NotNull - a nullable return value will never be null. But these attributes only affect nullable analysis for the callers of members that are annotated with them. So, you are indicating that your property can never return null or be set to null, despite nullable declaration

public sealed class MyOptions
{
    [NotNull, DisallowNull]public string? Name { get; set; }
}

和用法示例

var options = new MyOptions();
options.Name = null; //warning CS8625: Cannot convert null literal to non-nullable reference type.
options.Name = "test";

但是下一个示例未显示警告,因为可空分析尚未在对象初始化程序中正常运行,请参见GitHub问题

But the next example doesn't show a warning, because nullable analysis doesn't work properly in object initializers yet, see GitHub issue 40127 in Roslyn repository.

var options = new MyOptions { Name = null }; //no warning

(该问题已得到修复,于2020年3月以16.5版发布,应将VS更新到最新版本后消失.)

( This issue was fixed already, shipped in version 16.5 in March, 2020 and should go away after updating a VS to the latest version.)

属性获取器的图片相同,以下示例未显示任何警告,因为您指示可为空的返回类型不能为null

The same picture for property getter, the following sample doesn't show any warnings, because you indicated that nullable return type can't be null

var options = new MyOptions();
string test = options.Name.ToLower();

但是尝试设置null值并获取它会生成警告(编译器足够聪明,可以检测到这种情况)

but attempting to set a null value and get it generates a warning (compiler is smart enough to detect such scenarios)

var options = new MyOptions() { Name = null };
string test = options.Name.ToLower(); //warning CS8602: Dereference of a possibly null reference.

这篇关于可空引用类型和选项模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆