C# 8 是否注释可为空的属性和参数?

Does C# 8 annotate nullable properties and parameters?

我很好奇可空引用类型是如何工作的,不是在您自己的代码库中,而是在一个已经编译的库中。 C# 是否能够知道 属性 或参数是否可为 null,也许会检查某些编译器添加的属性是否存在?

Mads Torgersen(微软 C# 语言项目经理)在 Take C# 8.0 for a spin 中说:

If you call code that didn’t have the nullable reference types feature on (maybe it was compiled before the feature even existed), then we cannot know what the intent of that code was: it doesn’t distinguish between nullable and nonnullable – we say that it is "null-oblivious". So we give it a pass; we simply don’t warn on such calls.

所以不,他们似乎不会标记它,因此您不会收到任何类型的编译器警告。因此,在使用 C# 8 之前的代码时,您似乎必须做一些研究来确定引用是否可以包含 null,而不是依赖类型系统和编译器来警告您。

是的,如果库是使用 C# 8.0 编译器编译的,并且启用了可空引用类型,编译器将能够识别哪些值被标记为可空。

例如,考虑以下代码:

class C
{
    string NotNullProperty { get; set; }
    string? NullProperty { get; set; }

    void M(string notNullParameter, string? nullParameter) {}
}

It compiles roughly into:

[NonNullTypes(true)]
class C
{
    string NotNullProperty { get; set; }

    [Nullable]
    string NullProperty { get; set; }

    void M(string notNullParameter, [Nullable] string nullParameter) { }
}

注意可空的属性和参数被标记为[Nullable],整个class被标记为[NonNullTypes(true)],表明可空引用类型特性是为此启用。

另一方面,如果代码是在没有该功能的情况下编译的,它将被视为 "null-oblivious"。这意味着当您使用该代码时,编译器将不会产生与 null 相关的警告。

VS2019 预览版 1 和预览版 2 之间的行为似乎发生了变化,这可能是由于可空上下文的更改方式所致。不再有每个程序集或每个类型的属性。当然有可能还会再变

在 VS2019 预览版 2 中,表达可空或不可空信息(参数和 return 类型)的成员的每个部分都使用包含在程序集中的 NullableAttribute 单独归因必要时自己。该属性有两个构造函数:

NullableAttribute(byte)
NullableAttribute(byte[])

当 parameter/return 类型的可空性的每个方面都相同时,使用 byte 形式。 byte[] 当单个元素由于泛型或数组而混合为空时使用。在这两种情况下,1 用于 "not-nullable",2 用于 "nullable"。例如:

public class Test
{
    public string? Foo(string input) { ... }

    public List<string>? Bar() { ... }
}

编译为:

public class Test
{
    [return:Nullable(2)]
    public string Foo([Nullable(1)] string input) { ... }

    [return: Nullable(new byte[] { 1, 2 })]
    public List<string> Bar() { ... }
}

这允许检查程序集的任何代码(无论是使用它作为参考的编译器,还是其他工具)了解每个成员的意图。

我在 a blog post 中写了更多相关内容,但这应该足以理解要点。