引用类型超出 null 的基本原理

我是来自 C++ 背景的语言的新手,我很难理解允许引用类型为空的原因。


考虑以下片段


class Person {

  private string _name;

  public Person(string name) {_name = name;}


  void print() {

    Console.WriteLine(_name);

  }

}

现在没有什么可以阻止调用者执行以下操作


Person p = new Person(null);

p.print();

这会崩溃,如果 null 传递给构造函数,我可以通过抛出异常来保护它(不是真的),但这只是意味着如果它没有被捕获(我不能在 C# 中强制执行 AFAIK),我会在第一行崩溃,而不是第二行。


调用者必须阅读文档(这意味着我不能忘记记录构造函数可能抛出的内容)以了解所有这些。

  • 该语言允许空引用类型的(可能)原因是什么?

  • 这什么时候是有利的,而不仅仅是一个滴答作响的定时炸弹?我能想到的一种情况是延迟初始化,想要有条件地分配一个对象。

  • 我如何在我编写的代码中处理这个问题?


繁华开满天机
浏览 175回答 2
2回答

浮云间

该语言允许空引用类型的(可能)原因是什么?有时你想要一些没有价值的东西。例如,考虑具有父子关系的节点类。如果Parent永远不能为空,那将是非常不愉快的。即使在 C++ 中,指针也可以指向“无”,如0.我如何在我编写的代码中处理这个问题?从第一天起这就是一个问题。C# 团队一直希望我们作为开发人员通过进行足够的空检查来“修复”这个问题。这就是我们一直在做的事情。现在,在 C# 8(仍在开发中)有可以为null 的引用类型。启用后,如果将可能不为 null 的变量分配为 null 或可能为 null,您将收到编译器错误。

30秒到达战场

如果我们把问题反过来...由于您来自 C++,我们可以问“C++ 如何摆脱不能为空的引用”。简单的答案是“好吧,它有空指针,所以它不需要空引用”。有两种不同类型的变量来表示对对象的引用(具有非常不同的规则和语法)使 C++变得更加简单。是的,Tony Hoare声称空引用是他的“数十亿美元的错误”。但是,如果您无法表示未分配的引用,则很难使用简单的语法获得可工作的 C 系列语言。考虑这个简单的 C# 代码:string myString;if (condition) {&nbsp; &nbsp; myString = func1();} else {&nbsp; &nbsp; mystring = func2();}UseTheString(myString);字符串变量必须在外部作用域中声明。如果每个引用变量都需要在声明时初始化(如 C++ 引用),那么您需要使用一些会被丢弃几行的东西来初始化它。是的,你可能会说,这就是为什么string.Empty。比 System.String 更复杂的类型 - 构造成本更高的类型呢?他们是否需要都具有unassigned价值?这已经非常接近了null。嘿,JavaScript 有(空值和未赋值)!C++ 引用非常方便,但它们也很受限制。它们不仅在声明时必须被赋值,而且它们也是不可变的(变量 - 而不是它们引用的对象)。一旦声明并初始化 C++ 引用,就无法更改它所引用的内容。如果 C# 引用遵循此规则,则编写下面的代码会很有趣(忽略循环中的字符串连接几乎总是一个坏主意的事实):string myString = string.Empty;for (var i = 0; i < someValue; ++i) {&nbsp; &nbsp; myString = myString + SomeFunc(i);}然后,需要考虑一些自然为空的内容,例如关系数据库中可为空的内容。可空值类型 ( Nullable<T>) 出现在框架的第一个主要发布 v1 版本中也就不足为奇了。我们很多人都记得(我们中的一些人仍然在应付) DbNull 类型(和值)的痛苦。是的,处理空值是一种痛苦。大多数(但不是全部)语言中都有它。C# 语言(引用类型和值类型的组合共享一个变量语法)比 C++ 更容易阅读/理解/挑选。我发现我在 C# 中编写的错误比作为 C++ 程序员少得多(不过,在最近对语言进行所有更改之前,我是 90 年代的 C++ 程序员)。C# 8.0 人员认为他们有一个解决方案(这不是一个完整的解决方案,但它应该使空引用异常更加罕见)。我很好奇您对 C# 如何避免 Hoare 博士的十亿美元错误的看法。
打开App,查看更多内容
随时随地看视频慕课网APP