为什么在.NET中存在空?
为什么.NET中的值可以为null? 这是优于有一个保证,一切都会有一个价值,没有什么呼叫是空的?
任何人都知道这些方法被称为什么?
无论哪种方式,我对此都不是很了解,但是对于所有事情来说,没有任何价值可以让事情变得更简单,就简单性而言,也就是消除空检查,并且能够编写更多简化的algorithm,而无需分支检查。
在performance,简单,平行,面向未来等方面,每种风格有哪些优缺点?
作为一个没有null
的世界吸引人的是,它为许多现有的模式和结构提出了很多困难。 例如,考虑下面的结构,如果null
不存在,将会需要重大的改变
- 创build一个引用types数组ala:
new object[42]
。 在现有的CLR世界中,数组将被填充为非法的null
。 数组语义在这里需要改变很多 - 它使得
default(T)
仅在T
是值types时才有用。 在引用types或不受约束的generics上使用它是不被允许的 - 结构中的引用types字段需要被禁止。 CLR中的值types现在可以被初始化为0,它可以很方便地用
null
填充引用types的字段。 这在一个非空的世界中是不可能的,因此这个字段是struct中的引用types的字段需要被禁止
上述问题都不是无法解决的,但是它们确实导致了开发人员倾向于考虑编码的变化。 就我个人而言,我希望C#和.Net被devise为消除null,但不幸的是,它不是,我想像上面的问题有点与它有关。
我们有托尼·霍尔 ( Tony Hoare) ,一位早期的先驱,他曾为阿尔戈尔(Algol)工作过,感谢他。 他对此感到遗憾:
我把它称为我十亿美元的错误。 这是1965年空引用的发明。当时,我正在devise面向对象语言(ALGOL W)的第一个全面的引用types系统。 我的目标是确保所有引用的使用都是绝对安全的,编译器会自动执行检查。 但是,我忍不住引入空引用的诱惑,仅仅因为它很容易实现。 这导致了无数的错误,漏洞和系统崩溃,在过去的四十年里可能造成了十亿美元的痛苦和损失。
我认为,十亿是一个低球数。
这让我想起了詹姆斯·伯克(James Burke)的“连接”(Connections)系列,那里的僧侣正在把阿拉伯语翻译成拉丁文,最初遇到了一个零位。 罗马算术没有零表示,但阿拉伯语/阿拉伯语算术。 “为什么我们必须写一封信来表明什么?” 天主教僧侣争辩说。 “如果没什么,我们什么都不要写!”
对现代社会来说幸运的是,他们失去了论点,并学会了在math中写出零数字。 ;>
空只是表示没有对象。 有一些编程语言本身不具有“空”,但是其中大多数仍然有一些东西来表示没有合法的对象。 如果抛弃“null”并将其replace为“EmptyObject”或“NullNode”,它仍然是一个空名称。
如果删除编程语言的能力来表示不引用合法对象的variables或字段,也就是说,要求每个variables和字段总是包含一个真实且有效的对象实例,那么可以使一些非常有用和有效的数据结构尴尬和低效率,如build立一个链表。 程序员不是使用null来指示链表的末尾,而是强制创build“假”对象实例作为列表terminal,它们什么也不做,只是表示“这里什么都没有”。
深入到这里的存在主义,但是:如果你能performance出某种东西的存在,那么是不是也有一个基本的需要能够expression它的缺失呢?
我推测他们在.NET中存在null
,因为它(C#)紧跟在C ++ / Java脚步(并且只开始在更新的版本中分支)和VB / J ++(它成为VB.NET / J#)已经有了“无”价值的概念 – 也就是说,.NET由于什么原因而不是原来的原因而是null
。
在某些语言中没有null
概念 – null
可以被完全replace成一个像Maybe这样的types – 有Something(对象)或Nothing(但是这不是null
! 没有办法得到“Nothing”也许! )
在斯卡拉与选项:
val opt = Some("foo") // or perhaps, None opt match { case Some(x) => x.toString() // x not null here, but only by code-contract, eg Some(null) would allow it. case _ => "nothing :(" // opt contained "Nothing" }
这是通过 Haskell中的语言devise完成的 (根本不可能……根本不可能!)以及库支持和小心使用,比如在Scala中,如上所示。 (Scala支持null
– 可以说是用于Java / C#interop–但是可以在不使用这个事实的情况下编写Scala代码,除非null
允许“泄漏”)。
编辑:请参阅Scala:选项模式 , Scala:选项Cheat Cheet和SO:在Haskell中使用Maybetypes 。 大多数时候在Haskell中谈论Maybe也带来了Monad的话题。 我不会声称了解它们,但是这里是Maybe的使用的一个链接 。
快乐的编码。
好的,现在换行到C#-without-null的魔术字
class View { Model model; public View(Model model) { Console.WriteLine("my model : {0}, thing : {1}", this.model, this.model.thing); this.model = model; } }
控制台上打印什么?
- 没有关于访问一个未初始化的对象的exception抛出:确定调用这是一个NullReferenceException,这就是当前的世界。
- 它不会构build,用户需要在声明模型时指定一个值,请参阅最后一个项目符号点,因为它会创build相同的结果。
- 一些默认的模型和一些默认的东西:确定之前用null我们至less有一个方法来知道如果一个实例是正确的现在编译器正在产生奇怪的相似之处不包含任何东西,但作为模型仍然是无效的对象…
- 由对象的types定义的东西:更好的是,我们可以为每个对象定义一个特定的无效状态,但是现在每个可能无效的对象都需要独立地实现这个以及由调用者识别这个状态的方式。
所以基本上对我来说,似乎并没有解决任何事情去除空状态,因为可能无效的状态仍然需要pipe理。
呵呵,购买的方式是什么接口的默认值? 哦,抽象类当抽象类中定义的一个默认值调用一个方法,但调用另一个抽象的方法会发生什么? …. ….为什么哦为什么复杂的模型没有什么,这是多重遗传的问题从头再来!
一种解决scheme是彻底改变语法,去完成一个function完全的世界,在这个世界不存在的地方,只有当你想让它们存在的时候,Maybes才是…但是它不是C语言,多范式.Net将会丢失。
可能缺less的是一个空传播的运算符,它能够返回null给model.?.Thing
当模型为null时,就像model.?.Thing
哦,为了好好的回答你的问题:
- 当前的类库在Microsoft-Java崩溃之后发展起来,C#被构build为“更好的Java”,所以改变types系统以删除空引用将会是一个很大的改变。 他们已经设法引入价值types,并取消手动拳击!
- 由于值types介绍显示微软思考了很多关于速度…事实上,所有types的默认映射到零填充对于例如快速数组初始化非常重要。 否则参考值数组的初始化将需要特殊的威胁。
- 如果不与C进行空交互操作,至less在MSIL级别和不安全的块中是不可能的,因此它们需要被允许生存下来。
- 微软想用VB6 ++的框架去掉
Nothing
因为它在VB中调用会彻底改变语言,用户从VB6切换到VB.Net已经花费了好几年的时间,这种范例改变对于语言来说可能是致命的。
那么, 值 (值typesvariables)只能为null
因为可空types是在Fx2中引入的。
但是我想你的意思是:
为什么可以引用null
?
这是参考的有用性的一部分。 考虑一个树或LinkedList,它们将不可能(无法结束)没有null
。
你可以拿出更多的例子,但主要是null
模型的“可选”属性/关系的概念。
歇斯底里的葡萄干。
这是来自C级语言的宿醉,你在显式指针操作上生活。 现代的声明性语言(水星,哈斯克尔,OCaml等)相当幸福,没有空值。 在那里,每个价值都必须被明确地构build。 'null'的想法是通过'option'types来处理的,它有两个值'no'(对应于null)和'yes(x)'(对应非空值x)。 你必须解开每个选项的值来决定做什么,因此:没有空指针参考错误。
没有一个语言的空值可以节省你很多的悲痛,这真的是一个耻辱,这个想法仍然存在于高级语言中。
我不熟悉替代scheme,但是我没有看到Object.Empty和null之间的区别,除了null之外,让你知道当你的代码试图访问这个对象的时候什么是错误的,因为Object.Empty允许处理继续。 有时你想要一个行为,有时候你想要另一个。 区分Empty和Empty是一个有用的工具。
为了表示虚无的概念,因为0不合适。
现在你可以通过定义一个可为空的types来给任何值types一个空值。
我认为我们不可能总是为variables创造一个价值,因为一开始我们不得不将它默认为一些价值,这就出现了一个问题,为什么一个特定的价值会占据其他价值。
null
只是引用types的默认值的名称。 如果不允许null
,那么“没有价值”的概念不会消失,你只能以不同的方式来表示它。 除了有一个特殊的名字,这个默认值在它被滥用的情况下也有特殊的语义 – 也就是说,如果你把它看作是有价值的,而实际上没有。
如果没有null
:
- 你需要为你的types定义警戒默认值,以便在“没有值”的时候使用。 作为一个简单的例子,考虑一个前向单链表的最后一个节点。
- 您需要定义在所有这些标记值上执行的操作的语义。
- 运行时会有额外的开销来处理标记值。 在.NET和Java等现代虚拟机中,在大多数函数调用和解引用之前没有用于空检查的开销,因为CPU提供了特殊的方法来处理这种情况,并且CPU针对引用是非空的(例如分支预测)。
综上所述:
- 名字会改变,但这个概念不会。
- 在开发人员和开发人员文档中,定义和传递默认值和语义的负担是“没有价值”的情况。
- 在现代虚拟机上执行的代码将面临代码膨胀和许多algorithm显着的性能下降。
托尼·霍尔(Tony Hoare)描述的null
问题通常是由于在现代虚拟机之前,运行时系统几乎没有像现在这样对错误null
值的清理处理。 错误的指针/引用仍然是一个问题,但在使用.NET或Java时,跟踪问题往往比以前更容易在例如C.
很多人可能无法围绕没有空值的编码进行包装,如果C#没有空值,我怀疑它会被捕获到的程度。
这就是说,一个很好的select是,如果你想允许可空引用,那么引用将不得不显式为空,就像值types一样。
例如,
Person? person = SearchForPersonByFirstName("Steve"); if (person.HasValue) { Console.WriteLine("Hi, " + person.Value.FullName); }
不幸的是,当C#1.0出来时,没有Nullable的概念, 这是在C#2.0中添加的。 强制引用具有值会打破旧的程序。