第 89 講:C# 3 之隱式數(shù)組變量類型的初始化器
今天來看一個跟上一回不一樣又有點類似的新語法。
Part 1 引例
其中第二個的 new int[4]
的 4
可以不寫,即 new int[] { ... }
。但是有一個問題是,int
會被重復(fù)書寫一次。new int[4]
的 int
實際上是可以不寫的。因為在初始化器里,我們已經(jīng)可以清晰地獲取和了解到每一個元素的類型,1、2、3、4 都是 int
的字面量,那么 new T[]
的 T
就應(yīng)該是 int
。
可是,早期的語法并未對這個語法進(jìn)行簡化,C# 3 才開始意識到問題,于是得到了優(yōu)化。
Part 2 語法
C# 3 允許我們省略帶有初始化器的 new T[]
的 T
。注意這個說法,是必須帶有初始化器的。因為我們必須要從數(shù)組的初始化器辨識和了解到 T
的具體類型。如果初始化器不存在的話,我們不論如何都沒辦法獲得到 T
的實際結(jié)果。
可以對比一下就可以發(fā)現(xiàn),new[]
是一個全新的語法,它用于隱式初始化一個數(shù)組類型。
而且,這樣的語法可以拓展到多維的矩形數(shù)組里。如果數(shù)組是二維數(shù)組甚至是三維數(shù)組的話,都可以使用這個語法來初始化:
但是請注意。這里需要有一個限制。因為我們初始化器會給出全部的元素,因此我們完全可以通過初始化器推斷得到 new T[]
的中括號語法里的數(shù)字是多少。比如這個二維數(shù)組我們知道,它等于 new int[3, 3]
。
但是,因為簡化語法的關(guān)系,我們既然省略了數(shù)據(jù)類型在 new
的旁邊,那么自然而然也會需要省略掉這個沒必要寫出來的數(shù)字。因此,如果你寫的是這樣的語法:
它就不正確了。數(shù)字是沒必要寫出來的,所以你給出了數(shù)字還省略類型,C# 3 不會允許你這么做,因為沒必要寫出來還寫出來,寫出來還容易出錯。因此,這個語法不支持在中括號里顯式地給出數(shù)字。
綜上所述,我們來做個總結(jié)。下面四種寫法,可以對照注釋看看哪些可以哪些不行。
而對于變量已經(jīng)定義,但需要重新賦值的時候:
作為折衷的語法方案,new[] { ... }
的語法相對于 { ... }
僅初始化器語法要長一些,而比 new T[] { ... }
的語法來說又要短一點。但 { ... }
語法不能用于重新賦值,因此也不夠靈活。new[] { ... }
語法在初始化和重新賦值的時候都可以使用,因此還是很方便的。
Part 3 隱式數(shù)組類型的語法不依賴接收方
可以從代碼里看到,我們之所以要求省略類型的時候必須要有初始化器,是需要看初始化器的元素是什么類型,才能斷言和斷定具體的類型的。因此,它根本不依賴于接收方。
換句話說,我們才學(xué)到了 var
,那么我們下面這樣的語法也是可以的:
你說說,var
是什么,而 new[]
省略的類型又是什么?是不是 var
表示 int[]
,而 new[]
省略的是 int
???因為一個單純的元素就可以確定類型了,所以這樣的語法也可以。
再來看一個:
請問,每一個 new[]
都省略了什么類型,而 var
又表示什么?
答案是這樣的:
你答對了嗎?它是一個鋸齒數(shù)組,即使用兩個 string[]
類型為元素構(gòu)成的一維數(shù)組。注意,最外層的 new[]
這里省略的是 string[]
而不是 string
。
Part 4 隱式鋸齒數(shù)組類型的元素一致性
考慮下面這個例子:
new[]
那么問題來了,還有一個 new[]
,它應(yīng)該是什么類型呢?int
和 string
是毫不相關(guān)的兩個類型,根本無法找到合適的類型匹配。因此,C# 3 的這個語法要求,對于鋸齒數(shù)組來說,省略類型的時候必須要完全確定實際上的類型,才能省略。如果兩個和多個類型無法找到相同的類型匹配項,就會產(chǎn)生錯誤。
有人會問,new[]
可以是 new object[]
啊,畢竟 object
派生了 int
和 string
。但實際上,C# 3 并不支持這個匹配規(guī)則,隱式類型省略省略的類型,必須要求匹配項的元素全部類型都得一致。注意我這里說的是“一致”,也就意味著是相同類型才是 OK 的,而即使是兼容的類型(比如剛才說的 object
這樣的匹配邏輯)也是不行的。
例如這個復(fù)雜的賦值是錯誤的語法,需要讓其可以匹配,必須改成這樣: