C# 模模式
模模式其實(shí)就是我們之前的 { Length: _ }
或者 { Count: _ }
。這個(gè)其實(shí)就是屬性模式的一種特例——屬性名恰好是 Length
或 Count
而已,只是在 C# 11 里單獨(dú)為這兩個(gè)特殊的屬性模式匹配的邏輯有所加強(qiáng):它的代碼內(nèi)容會(huì)影響編譯器分析代碼。
模模式的原名叫長(zhǎng)度模式(Length Pattern),不過(guò)在模式匹配里,C# 定義了
Length
和Count
可以提供和參與編譯器分析非負(fù)性的屬性名稱,length 這個(gè)單詞可以叫長(zhǎng)度,但 count 不能。因?yàn)?count 記錄的是元素總個(gè)數(shù),你只能說(shuō)集合有多少元素,而不能說(shuō)集合長(zhǎng)度是多少。從定義和名稱叫法上 count 和 length 有區(qū)別,所以本文改了一個(gè)說(shuō)法。這個(gè)模模式的模就是長(zhǎng)度的意思,而它恰好就具有兩種不同類型 length 和 count 都可涵蓋的含義,所以本文介紹的時(shí)候?qū)⑵浞Q為模模式。其中英語(yǔ)術(shù)語(yǔ)里的 cardinality 是基數(shù)的意思,指的是集合里有多少個(gè)元素;不過(guò)在計(jì)算機(jī)科學(xué)范疇,cardinality 除了翻譯成基數(shù)以外,還可以被翻譯為“勢(shì)”。比如說(shuō)兩個(gè)集合等勢(shì)就意味著兩個(gè)集合的元素是一一對(duì)應(yīng)起來(lái)的。這里用不著這么復(fù)雜的概念,我們只需要知道它的基本用法表元素總數(shù)就可以了。不過(guò),如果你在查資料的時(shí)候請(qǐng)仍然按照“長(zhǎng)度模式”這個(gè)術(shù)語(yǔ)去查閱,只是本文為了避免二義性和語(yǔ)義沖突而換了一個(gè)說(shuō)法。
早期的長(zhǎng)度模式只是一個(gè)簡(jiǎn)單的屬性判斷,但在 C# 11 里有了列表模式和分片模式,因此在集合里,長(zhǎng)度的分析過(guò)程變得非常重要。
1、系統(tǒng)類型的長(zhǎng)度屬性均假設(shè)為非負(fù)數(shù)
C# 11 開(kāi)始,系統(tǒng)提供的集合類型里,只要它帶有 Length
或 Count
屬性的話,那么編譯器會(huì)自動(dòng)假設(shè)它非負(fù)。換句話說(shuō),雖然我們大家都知道,Length
和 Count
屬性返回值是 int
,它有負(fù)整數(shù)的范圍,但集合的元素總數(shù)是不可能為負(fù)數(shù)的(哪怕是空集合,長(zhǎng)度也是 0,也并非負(fù)數(shù))。因此,系統(tǒng)會(huì)假設(shè)這些數(shù)據(jù)類型(特別是一維數(shù)組類型需要注意)一定是非負(fù)長(zhǎng)度。如果你使用如下代碼,編譯器會(huì)自動(dòng)報(bào)錯(cuò):
并提示你,數(shù)組的長(zhǎng)度非負(fù),因此這個(gè)屬性模式將永遠(yuǎn)不會(huì)匹配成功。
2、自定義類型的長(zhǎng)度模式對(duì)編譯器的表現(xiàn)行為
這里說(shuō)一下編譯器的處理機(jī)制。不論是你定義的集合類型,還是系統(tǒng)給定的數(shù)據(jù)類型里,長(zhǎng)度的非負(fù)性質(zhì)一直是一個(gè)正常的邏輯實(shí)現(xiàn)。雖然你可以隨意給 Length
或 Count
屬性設(shè)置為一個(gè)負(fù)數(shù)值,但它并不是正確的實(shí)現(xiàn),因?yàn)殚L(zhǎng)度在使用的時(shí)候一定是非負(fù)的,雖然它的返回值是 int
類型包含負(fù)數(shù)的數(shù)值范圍。
使用 int
類型但不允許非負(fù)的原因是因?yàn)椋?/span>uint
類型雖然能夠保證非負(fù),但它不符合 CLS(公共語(yǔ)言運(yùn)行時(shí))的標(biāo)準(zhǔn),也就是說(shuō),這樣的代碼可能只能在 C# 上跑,而同一個(gè) DLL 文件編譯出來(lái)之后,VB 對(duì)這個(gè) uint
不支持,因此無(wú)法使用這樣的代碼。因此為了兼容性,我們?cè)O(shè)置了 int
作為理想的返回類型。
而編譯器會(huì)先查看這個(gè)數(shù)據(jù)類型是否同時(shí)包含一個(gè)索引器和一個(gè) Length
或 Count
屬性。如果同時(shí)存在,那么既然你都能索引了,這個(gè)類型的長(zhǎng)度就一定不可為負(fù)數(shù)。但是,如果你沒(méi)有索引器,但只包含一個(gè)單純的 Length
或 Count
屬性的話,編譯器會(huì)認(rèn)為它是普通的屬性,因此不會(huì)驗(yàn)證負(fù)數(shù)情況。
所以總的來(lái)說(shuō),必須同時(shí)包含索引器和長(zhǎng)度屬性(Length
或 Count
其一)的時(shí)候,編譯器才會(huì)假設(shè)長(zhǎng)度屬性的結(jié)果一定非負(fù)。
3、同時(shí)包含 Length
和 Count
屬性的時(shí)候
如果一個(gè)集合同時(shí)包含 Length
和 Count
屬性的話,C# 團(tuán)隊(duì)的解決辦法是,只驗(yàn)證其中的 Length
屬性一定非負(fù),而 Count
屬性就不再會(huì)假設(shè)為非負(fù)的情況。舉個(gè)例子。
Length
屬性會(huì)得到非負(fù)數(shù)的假設(shè)。而 Count
屬性不論什么時(shí)候也不會(huì)被假設(shè)為非負(fù)的,因此這段代碼里,如果 list