欢迎光临散文网 会员登陆 & 注册

第 89 讲:C# 3 之隐式数组变量类型的初始化器

2022-02-21 10:14 作者:SunnieShine  | 我要投稿

今天来看一个跟上一回不一样又有点类似的新语法。

Part 1 引例

我们在学习 C# 基本语法的时候我们知道,数组的初始化有两种写法:

其中第二个的 new int[4]4 可以不写,即 new int[] { ... }。但是有一个问题是,int 会被重复书写一次。new int[4]int 实际上是可以不写的。因为在初始化器里,我们已经可以清晰地获取和了解到每一个元素的类型,1、2、3、4 都是 int 的字面量,那么 new T[]T 就应该是 int

可是,早期的语法并未对这个语法进行简化,C# 3 才开始意识到问题,于是得到了优化。

Part 2 语法

C# 3 允许我们省略带有初始化器new T[]T。注意这个说法,是必须带有初始化器的。因为我们必须要从数组的初始化器辨识和了解到 T 的具体类型。如果初始化器不存在的话,我们不论如何都没办法获得到 T 的实际结果。

可以对比一下就可以发现,new[] 是一个全新的语法,它用于隐式初始化一个数组类型。

而且,这样的语法可以拓展到多维的矩形数组里。如果数组是二维数组甚至是三维数组的话,都可以使用这个语法来初始化:

但是请注意。这里需要有一个限制。因为我们初始化器会给出全部的元素,因此我们完全可以通过初始化器推断得到 new T[] 的中括号语法里的数字是多少。比如这个二维数组我们知道,它等于 new int[3, 3]

但是,因为简化语法的关系,我们既然省略了数据类型在 new 的旁边,那么自然而然也会需要省略掉这个没必要写出来的数字。因此,如果你写的是这样的语法:

它就不正确了。数字是没必要写出来的,所以你给出了数字还省略类型,C# 3 不会允许你这么做,因为没必要写出来还写出来,写出来还容易出错。因此,这个语法不支持在中括号里显式地给出数字。

综上所述,我们来做个总结。下面四种写法,可以对照注释看看哪些可以哪些不行。

而对于变量已经定义,但需要重新赋值的时候:

作为折衷的语法方案,new[] { ... } 的语法相对于 { ... } 仅初始化器语法要长一些,而比 new T[] { ... } 的语法来说又要短一点。但 { ... } 语法不能用于重新赋值,因此也不够灵活。new[] { ... } 语法在初始化和重新赋值的时候都可以使用,因此还是很方便的。

Part 3 隐式数组类型的语法不依赖接收方

可以从代码里看到,我们之所以要求省略类型的时候必须要有初始化器,是需要看初始化器的元素是什么类型,才能断言和断定具体的类型的。因此,它根本不依赖于接收方。

换句话说,我们才学到了 var,那么我们下面这样的语法也是可以的:

你说说,var 是什么,而 new[] 省略的类型又是什么?是不是 var 表示 int[],而 new[] 省略的是 int 啊?因为一个单纯的元素就可以确定类型了,所以这样的语法也可以。

再来看一个:

请问,每一个 new[] 都省略了什么类型,而 var 又表示什么?

答案是这样的:

你答对了吗?它是一个锯齿数组,即使用两个 string[] 类型为元素构成的一维数组。注意,最外层的 new[] 这里省略的是 string[] 而不是 string

Part 4 隐式锯齿数组类型的元素一致性

考虑下面这个例子:

这个语法其实是一个错误的语法。首先我们可以推断大括号内的两个 new[] 的实际类型:

那么问题来了,还有一个 new[],它应该是什么类型呢?intstring 是毫不相关的两个类型,根本无法找到合适的类型匹配。因此,C# 3 的这个语法要求,对于锯齿数组来说,省略类型的时候必须要完全确定实际上的类型,才能省略。如果两个和多个类型无法找到相同的类型匹配项,就会产生错误。

有人会问,new[] 可以是 new object[] 啊,毕竟 object 派生了 intstring。但实际上,C# 3 并不支持这个匹配规则,隐式类型省略省略的类型,必须要求匹配项的元素全部类型都得一致。注意我这里说的是“一致”,也就意味着是相同类型才是 OK 的,而即使是兼容的类型(比如刚才说的 object 这样的匹配逻辑)也是不行的。

例如这个复杂的赋值是错误的语法,需要让其可以匹配,必须改成这样:


第 89 讲:C# 3 之隐式数组变量类型的初始化器的评论 (共 条)

分享到微博请遵守国家法律