【发布时间】:2020-08-26 11:01:10
【问题描述】:
这不是我关于可空引用类型的第一个问题,因为我已经使用它几个月了。但我体验得越多,我就越感到困惑,我越看不到该功能所增加的价值。
以这段代码为例
string? nullableString = default(string?);
string nonNullableString = default(string);
int? nullableInt = default(int?);
int nonNullableInt = default(int);
执行给出:
nullableString=>null
nonNullableString=>null
nullableInt=>null
nonNullableInt=>0
(不可为空的)整数的默认值一直是0,但是
对我来说,不可为空的字符串的默认值为null 是没有意义的。
为什么选择这个?这与我们一直习惯的不可为空的原则背道而驰。
我认为默认的不可为空字符串的默认值应该是String.Empty。
我的意思是在 C# 实现的深处,必须指定 0 是 int 的默认值。我们也可以选择1 或2,但不,共识是0。那么当 Nullable 引用类型功能被激活时,我们不能只指定 string 的默认值是 String.Empty 吗?此外,微软似乎希望在不久的将来在 .NET 5 项目中默认激活它,因此此功能将成为正常行为。
现在是一个对象的同一个例子:
Foo? nullableFoo = default(Foo?);
Foo nonNullableFoo = default(Foo);
这给出了:
nullableFoo=>null
nonNullableFoo=>null
再一次,这对我来说没有意义,在我看来,Foo 的默认值应该是new Foo()(如果没有可用的无参数构造函数,则会出现编译错误)。
为什么默认设置为 null 一个不应为 null 的对象?
现在进一步扩展这个问题
string nonNullableString = null;
int nonNullableInt = null;
编译器对第一行给出警告,通过我们的.csproj 文件中的简单配置可以将其转换为错误:<WarningsAsErrors>CS8600</WarningsAsErrors>。
它按预期给出了第二行的编译错误。
所以不可为空的值类型和不可为空的引用类型之间的行为是不一样的,但这是可以接受的,因为我可以覆盖它。
但是当这样做时:
string nonNullableString = null!;
int nonNullableInt = null!;
编译器在第一行完全没问题,根本没有警告。
我最近在体验可空引用类型功能时发现了null!,我希望编译器对于第二行也可以,但事实并非如此。现在我真的很困惑为什么微软决定实现不同的行为。
考虑到它根本不能防止 null 在不可为空的引用类型变量中出现,看来这个新特性并没有改变任何东西,也根本没有改善开发人员的生活(与非- 可空值类型,不能为空,因此不需要进行空检查)
所以最后看来,唯一的增值只是在签名方面。开发人员现在可以明确方法的返回值是否为 null,或者属性是否为 null(例如,在数据库表的 C# 表示中,NULL 是列中的允许值)。
除了我不知道如何有效地使用这个新功能之外,您能否给我提供其他有用的示例来说明如何使用可为空的引用类型? 我真的很想好好利用这个功能来改善我的开发人员的生活,但我真的不明白如何......
谢谢
【问题讨论】:
-
您忽略了
string nonNullableString = default(string);生成的警告,这就是您看不到任何好处的原因。您将null显式存储到不可为空的变量中,因此编译器会抱怨告诉您出了点问题。这就是此功能的好处,尤其是当您将警告视为错误时。 -
我没有忽略这些警告,事实上我现在的配置是
<WarningsAsErrors>CS8600;CS8625</WarningsAsErrors>。我只是对为什么这甚至可能感到非常困惑。我们永远无法确定不可为空的引用类型不会为空,但是对于值类型,我们可以确定... -
我在下面回答了您问题的优点部分。顺便说一句,我建议您在此处询问时尝试使用负载较少的语言。您选择的词语(“它没有意义”、“它完全违背了我们一直习惯的(...)原则”)使您的问题读起来更像是咆哮而不是诚实的询问。人们不喜欢被骂,所以如果 Roslyn 团队的真正程序员读到你的帖子,他们可能会少一点“让我们帮助这个人理解”的态度,而多一点“保护自己免受敌意”的态度,这对讨论没有帮助。
-
@JérômeMEVEL 许多“明显”无效/损坏的代码在语法上完全合法,并且不能被检测为损坏......还有很多完全安全和合法的东西 在计算上是不可能证明有效的(参见“停止问题”)。编译器的工作是阻止确定 问题,尝试警告您可能出现的问题,但在您可能正确时不要主动妨碍您。在这种情况下:它给了你一个警告——你还想要什么?
-
@V0ldek 非常感谢您的长篇回答并对我的措辞感到抱歉,英语不是我的母语。只是*咆哮*`不是我的目标,但我想说明为什么这个功能的行为让我很困惑,以便获得不同的意见并更好地理解它
标签: c# c#-8.0 nullable-reference-types non-nullable