可空引用类型-根据接受的参数返回类型的可为空性

4

我有一个方法叫Foo,接受一个字符串参数。如果这个字符串参数是null,那么它会执行一些操作;如果不是null(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应该接受可空字符串,因为它支持null和非null值。我改变了它的参数和返回类型为string?

string? Foo(string? s)
{
    // Do something with s.
    return s;
}

这次是关于 string s2 = Foo(s) 的问题,它抱怨 Foo 返回了一个 string?,而我试图将其赋值给一个 string
有没有办法让流分析理解这样一个事实:当我提供一个 string 给 Foo(而不是一个 string?)时,它的返回值就不可能为 null?

这能在一个方法中实现吗?不行。 - mjwills
1
尽管从理论上讲,编写一个跟踪“该方法是否从其输入到输出保留了空值性?”的流分析器是可能的,但实践中通常不是这样做的。 - Eric Lippert
3
我希望代码契约得到广泛应用。 - Şafak Gür
1
我也有同感,但他们确实陷入了尴尬的境地。虽然库和重写器功能强大,但我们并没有觉得有充分的理由将其集成到语言中,但从用户角度来看,如果它们不是“免费”提供的,那么人们并不认为代价值得收益。我对整个过程有些遗憾。 - Eric Lippert
2
我们正在考虑一些属性来帮助处理这种情况。这个具体的场景将使用 [NullInNullOut](名称尚未确定)。https://github.com/dotnet/roslyn/issues/26761 - Julien Couvreur
太好了。泛型是否正在考虑中?C<string?> M(C<string?> arg) - Şafak Gür
2个回答

1
当参数s不为空时,这可能会使返回值不为空。
// using System.Diagnostics.CodeAnalysis;

[return: NotNullIfNotNull("s")]
string? Foo(string? s)
{
    // Do something with s.
    return s;
}

具体来说:这是在dotnet/roslyn#37201中实现的,并在指定条件后置条件:NotNullWhenMaybeNullWhenNotNullIfNotNull中有所记录。 - Kevinoid

-1

是的,只需要两种方法。一个接受一个string?并返回一个string?,另一个接受一个string并返回一个string。你可能想用后者来实现前者(检查是否为null,如果非null,则调用另一个方法,否则处理null的情况)。

有两个方法可以确保返回类型根据输入类型而异。


当前,无法在Visual Studio 2019的第一个预览版上工作。Nullability不会影响方法签名。 - Şafak Gür
5
仅基于可空性无法进行重载。如果微软将可空性作为 modopt,则可以实现,但我认为这不是计划中的做法。 - Eric Lippert
1
将可空引用类型添加到现有项目中似乎会像我在1990年代中期参与的一个项目一样有趣,当时我们需要将一个由经验丰富的C程序员编写的合理大小的C++项目添加const,以便它可以与我们采用的严格启用const的库进行交互。那真的一点都不好玩(尽管它确实导致了更加稳固的代码)。 - Flydog57

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接