我很好奇可空引用类型的工作方式,而不是在您自己的代码库中,而是在已经编译的库中。 C#是否可以知道某个属性或参数是否可以为空,也许可以检查某些编译器添加的属性是否存在?
答案 0 :(得分:6)
是的,如果该库是使用C#8.0编译器编译的,并且可空引用类型已打开,则编译器将能够识别哪些值被标记为可空。
例如,考虑以下代码:
class C
{
string NotNullProperty { get; set; }
string? NullProperty { get; set; }
void M(string notNullParameter, string? nullParameter) {}
}
[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,而不是依靠类型系统和编译器来警告您。