gpt4 book ai didi

c# - 为什么我没有收到关于在 C# 8 中使用结构的类成员可能取消引用 null 的警告?

转载 作者:行者123 更新时间:2023-12-03 21:25:51 24 4
gpt4 key购买 nike

在带有 nullable reference types 的 C# 8 项目中启用,我有以下代码我认为应该给我一个关于可能的空取消引用的警告,但没有:

public class ExampleClassMember
{
public int Value { get; }
}

public struct ExampleStruct
{
public ExampleClassMember Member { get; }
}

public class Program
{
public static void Main(string[] args)
{
var instance = new ExampleStruct();
Console.WriteLine(instance.Member.Value); // expected warning here about possible null dereference
}
}

instance使用默认构造函数初始化, instance.Member设置为默认值 ExampleClassMember ,即 null .因此, instance.Member.Value将抛出 NullReferenceException在运行时。据我了解 C# 8 的可空性检测,我应该得到一个关于这种可能性的编译器警告,但我没有;这是为什么?

最佳答案

请注意,在调用 Console.WriteLine() 时没有理由发出警告。 .引用类型属性不是可为空的类型,因此编译器无需警告它可能为空。

您可能会争辩说编译器应该警告 struct 中的引用。本身。这对我来说似乎是合理的。但是,事实并非如此。这似乎是一个漏洞,由值类型的默认初始化引起,即必须始终有一个默认(无参数)构造函数,它总是将所有字段清零(引用类型字段为空,数字类型为零等。 )。

我称之为漏洞,因为理论上不可为空的引用值实际上应该始终是非空的!呃。 :)

这个漏洞似乎在这篇博客文章中得到了解决:Introducing Nullable Reference Types in C#

Avoiding nulls So far, the warnings were about protecting nulls in nullable references from being dereferenced. The other side of the coin is to avoid having nulls at all in the nonnullable references.

There are a couple of ways null values can come into existence, and most of them are worth warning about, whereas a couple of them would cause another “sea of warnings” that is better to avoid:

  • Using the default constructor of a struct that has a field of nonnullable reference type. This one is sneaky, since the default constructor (which zeroes out the struct) can even be implicitly used in many places. Probably better not to warn [emphasis mine - PD], or else many existing struct types would be rendered useless.


换句话说,是的,这是一个漏洞,但不,这不是错误。语言设计者意识到了这一点,但选择将这种情况排除在警告之外,因为以 struct 的方式不这样做是不切实际的。初始化工作。

请注意,这也符合该功能背后的更广泛理念。来自同一篇文章:

So we want it to complain about your existing code. But not obnoxiously. Here’s how we are going to try to strike that balance:

  1. There is no guaranteed null safety [emphasis mine - PD], even if you react to and eliminate all the warnings. There are many holes in the analysis by necessity, and also some by choice.

To that last point: Sometimes a warning is the “correct” thing to do, but would fire all the time on existing code, even when it is actually written in a null safe way. In such cases we will err on the side of convenience, not correctness. We cannot be yielding a “sea of warnings” on existing code: too many people would just turn the warnings back off and never benefit from it.



另请注意,名义上不可为空的引用类型的数组也存在同样的问题(例如 string[] )。创建数组时,所有引用值为 null ,但这是合法的,不会产生任何警告。

这么多解释为什么事情是这样的。那么问题就变成了,该怎么办呢?这要主观得多,我认为没有正确或错误的答案。那就是说……

我个人会对待我的 struct根据具体情况分类型。对于意图实际上是可为空的引用类型的那些,我将应用 ?注解。否则,我不会。

从技术上讲, struct 中的每个引用值应该是“可空的”,即包括 ?具有类型名称的可空注释。但是与许多类似的特性(如 C# 中的 async/await 或 C++ 中的 const)一样,这具有“传染性”方面,因为您需要稍后覆盖该注释(使用 ! 注释),或者包括一个显式的空检查,或者只将该值分配给另一个可以为空的引用类型变量。

对我来说,这违背了启用可为空引用类型的许多目的。由于 struct 的此类成员无论如何,类型在某些时候都需要特殊情况处理,因为在仍然能够使用不可为空引用类型的同时真正安全地处理它的唯一方法是在使用 struct 的任何地方进行空检查。 , 我觉得在代码初始化 struct 时接受是一个合理的实现选择,代码有责任正确地执行此操作并确保不可为空的引用类型成员实际上已初始化为非空值。

这可以通过提供一种“官方”的初始化方式来帮助,例如非默认构造函数(即带有参数的构造函数)或工厂方法。仍然存在使用默认构造函数或根本不使用构造函数的风险(如在数组分配中),但通过提供一种方便的方法来初始化 struct正确地,这将鼓励使用它的代码避免在不可空变量中的空引用。

也就是说,如果您想要的是 100% 安全的可空引用类型,那么显然,实现该特定目标的正确方法是始终注释 struct 中的每个引用类型成员。与 ? .这意味着每个字段和每个自动实现的属性,以及直接返回此类值或此类值的乘积的任何方法或属性 getter 。然后,消费代码将需要在将此类值复制到不可为空的变量中的每个点包含空检查或容空运算符。

关于c# - 为什么我没有收到关于在 C# 8 中使用结构的类成员可能取消引用 null 的警告?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58425298/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com