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

时间:2018-12-06 20:11:32

标签: c# .net c#-8.0

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

3 个答案:

答案 0 :(得分:6)

是的,如果该库是使用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],并且整个类都被标记为[NonNullTypes(true)],表示已为它启用了可为空的引用类型功能。

另一方面,如果代码是在没有功能的情况下编译的,则将其视为“无空”。这意味着当您使用该代码时,编译器不会产生与空相关的警告。

答案 1 :(得分:3)

在VS2019 Preview 1和Preview 2之间,行为似乎已更改,这可能是由于可空上下文的更改方式所致。不再有按装配或按类型的属性。当然,它可能会再次改变

在VS2019 Preview 2中,表示可空或不可空信息(参数和返回类型)的成员的每个部分都使用NullableAttribute单独赋予属性,该元素在必要时包含在程序集本身中。此属性具有两个构造函数:

NullableAttribute(byte)
NullableAttribute(byte[])

当该参数/返回类型的可空性的每个方面都相同时,将使用byte格式。由于泛型或数组,当单个元素具有可空性混合时,使用byte[]。在这两种情况下,1表示“不可为空”,2表示为“可为空”。例如:

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中对此进行了详细介绍,但这应该足以理解要点。

答案 2 :(得分:1)

Take C# 8.0 for a spin中,Mads Torgersen(Microsoft C#语言程序经理)说:

  

如果您调用不具有可为空的引用类型功能的代码(也许它是在该功能还没有存在之前就被编译的),那么我们将不知道该代码的意图是什么:它无法区分可为空的引用类型和不可为空–我们说它是“不可忽略的”。所以我们给它通行证;我们根本不会发出警告。

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