先让我们来看个代码:
T? Cast<T>(object? obj) {
return (T?)obj;
}
这段代码某些情况下会在 return 语句这一行产生一个空引用异常(NullReferenceException,常简称为 NRE),来猜猜为什么呢?
是的,写这篇文章的起因是 C# 这个东西在把空引用转换到值类型的时候会产生 NRE 然后什么额外信息都不报,于是让我 debug 了一下午才找出来这个破烂 NRE 到底在哪。
看到这里你可能会心一笑,那说明你大概率不是这篇文章的受众;你也可能半懵半醒着,那就对了,这篇文章就要把广泛隐藏在 C# 泛型和类型系统里面那些不干人事的妙妙小特性从头到尾翻个遍。
C# 强大的类型系统
让我们从 C# 这门语言的诞生讲起。
20 世纪 90 年代,微软发布了 Microsoft Visual J,在 Java 的基础上添加了很多自己的特性,使其可以更方便地调用 Win32 API 和 ActiveX 等。然而好景不长,1997 年,Sun 以违反合约为理由(实际上就是想捞钱)起诉微软并索赔,迫使微软遵守 Java 的跨平台和生态共享原则。然后呢,微软肯定不能任 Sun 无理取闹,直接撂一边不干了,开始在自己的生态中逐步淘汰 JVM,并最终在 2004 年结束了 J 的支持。
但 JVM 开始被淘汰,Windows 却又迫切需要一个具有 Java 相似优势的软件开发平台。于是,在 2000 年,微软在开发者大会上发布了自己的编程语言——C#。C# 出自同样是 J++ 创始人的 Anders Hejlsberg 之手(没错这人还是 Turbo Pascal 的创始人和 TypeScript 的首席开发者,一辈子专注于造语言改变世界,顶级大佬了属于是),极大程度上吸收了同年代的 Java、C++、VB 等等语言的各种特点,尤其是 Java。因此,C# 常被戏称为 Microsoft Java,就是因为它跟 Java 在很多方面极其相似。
讲了这么多有什么用呢?你一定注意到了,C# 这个语言与 Java 有着千丝万缕的联系,也正因此,C# 的很多特性就是直接从 Java 抄过来的:像是类、对象、引用、继承、接口等等,全是跟 Java 几乎一模一样的特性。同时,它又要保持跟 Java 的相似性以接纳由于逐步淘汰 JVM 而转向 .NET 平台的开发者,让他们上手难度尽可能低。这些原因融合在一起,就决定了 C# 一定会在很大程度上保留 Java 那套特性,但微软又要追求自己的高性能和各种新奇特性,就导致这门语言变成了很多神奇的东西跑在一起的样子。这里要讲的类型系统,也正是因此,才变得如此复杂。
好了步入正题。
未完待续
喜欢的话,留下你的评论吧~