可空引用类型 - 通过接受的参数返回类型可空性

Posted

技术标签:

【中文标题】可空引用类型 - 通过接受的参数返回类型可空性【英文标题】:Nullable reference types - return type nullability by the accepted parameter 【发布时间】:2019-06-02 14:40:38 【问题描述】:

我有一个方法,Foo,它接受一个字符串。如果字符串为空,它会做一些事情,如果不是,它会做一些其他事情(null 是一个有效值)。然后它返回相同的字符串。

这是在 C# 8.0 中具有可空引用类型已禁用的 Foo:

string Foo(string s)

    // Do something with s.
    return s;


void Bar()

    string s = "S";
    string s2 = Foo(s);

    string n = null;
    string n2 = Foo(n);

启用可空引用类型后,string n = null 会发出警告。这是有道理的,因为 string 不再可以为空。我将其类型转换为string?:

void Bar()

    string s = "S";
    string s2 = Foo(s);

    string? n = null; // X
    string? n2 = Foo(n);

现在Foo(n) 警告我 Foo 对可空字符串的新厌恶。这也很有意义 - Foo 应该接受一个可为空的字符串,因为它同时支持空值和非空值。我更改了它的参数,因此返回类型为string?

string? Foo(string? s)

    // Do something with s.
    return s;

这次是 string s2 = Foo(s),抱怨 Foo 返回了 string?,而我试图将其分配给 string

有没有办法让流分析理解这样一个事实,即当我向 Foo 提供 string(而不是 string?)时,它的返回值不能为空?

【问题讨论】:

这可以在单一方法中实现吗?没有。 虽然理论上可以编写一个流分析器来跟踪“这种方法从输入到输出是否保留了可空性?”在实践中,通常情况并非如此。 我希望代码合同已经起飞。 是的,我也是,但他们确实陷入了尴尬的境地。库和重写器足够强大,以至于我们觉得我们没有充分的理由将其集成到语言中,但用户的观点是它们并没有那么引人注目,以至于人们觉得如果不这样做,成本就值得收益有“免费”的语言。我对这一切的结果感到有些遗憾。 我们正在考虑一些属性来帮助解决这种情况。此特定场景将使用[NullInNullOut](名称尚未确定)。 github.com/dotnet/roslyn/issues/26761 【参考方案1】:

这可以使参数s不为空时返回值不为空。

// using System.Diagnostics.CodeAnalysis;

[return: NotNullIfNotNull("s")]
string? Foo(string? s)

    // Do something with s.
    return s;

【讨论】:

详细说明:这是在dotnet/roslyn#37201 中实现的,并记录在Specify conditional post-conditions: NotNullWhen, MaybeNullWhen, and NotNullIfNotNull 中。【参考方案2】:

是的,只有两种方法。一个接受string? 并返回string?,另一个接受string 并返回string。您可能希望根据后者来实现前者(检查 null,如果非 null,则调用其他方法,否则,处理 null 情况)。

拥有两种方法可以确保返回类型因输入类型而异。

【讨论】:

目前,不适用于 Visual Studio 2019 的第一个预览版。可空性对方法签名没有影响。 您不能仅基于可空性重载。如果 MSFT 将可空性设为 modopt,那么它会起作用,但我相信这不是计划。 向现有项目添加可空引用类型似乎与我在 1990 年代中期从事的一个项目一样有趣,该项目采用了一个合理大小的 C++ 项目(由经验丰富的 C 程序员编写)和将const 添加到它,以便它与我们采用的严格的const-enable 库正确互操作。这一点都不好玩(尽管它确实产生了更可靠的代码)。

以上是关于可空引用类型 - 通过接受的参数返回类型可空性的主要内容,如果未能解决你的问题,请参考以下文章

Firebase,Swift:返回类型上的可空性说明符冲突,“可空”与现有说明符“非空”冲突

想要启用可空引用类型时如何处理可选参数?

具有泛型返回类型的可空引用类型

Kotlin中与Java互操作与可空性类型映射属性访问@JvmOverloads@JvmField@JvmStatic@Throws和函数类型操作详解

何时在启用可空引用类型的情况下对参数进行空检查

引用类型与可空类型 ToString()