最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

C# 屬性模式

2023-01-15 10:51 作者:SunnieShine  | 我要投稿

1、語(yǔ)法

屬性模式是用于專門(mén)體現(xiàn)對(duì)象的屬性信息的匹配模式。我們使用一對(duì)大括號(hào)來(lái)表達(dá)參數(shù)是否必須滿足這個(gè)數(shù)值信息。

假如,我們現(xiàn)在的 Point 類型的 XY 不再使用字段表達(dá),而是用屬性來(lái)表達(dá):

那么,我們即使不給出解構(gòu)函數(shù),也可以使用屬性的方式來(lái)對(duì)每一個(gè)成員信息進(jìn)行判斷:

屬性模式專門(mén)給屬性提供數(shù)據(jù)判斷的服務(wù),因此這種模式叫屬性模式。

2、屬性模式的棄元

一般來(lái)說(shuō),屬性模式下,由于不需要依賴于解構(gòu)函數(shù),因此屬性是可以寫(xiě)出來(lái)判斷的;反過(guò)來(lái)說(shuō),如果屬性不判斷的話,那么寫(xiě)出來(lái)就沒(méi)意義了。不過(guò) C# 的語(yǔ)法允許我們使用棄元來(lái)默認(rèn)通過(guò)某個(gè)屬性的判定:

這樣的話,Y 屬性是永真式,即不用判斷了。說(shuō)白了,這里的 Y: _ 是可以不寫(xiě)的。只是 C# 允許這種語(yǔ)法存在,體現(xiàn)出了語(yǔ)法的靈活性。

3、空屬性模式及變量聲明內(nèi)聯(lián)

如果屬性模式里的成員為空,那么它表示什么呢?

是的,對(duì)于可空類型(不管是值類型也好,還是引用類型也好),都表示“不為 null”。比如 nullable 是一個(gè)可空的 Point 類型,那么 is { } 就表示 nullable.HasValue。當(dāng)滿足條件后,我們用 point 表示這個(gè) Point 類型的數(shù)據(jù)。

從這個(gè)例子里,我們可以得到的若干信息是這些:

  1. is { } 表示“不為 null”,適用于任何可為空的類型;

  2. 大括號(hào)后可繼續(xù)內(nèi)聯(lián)一個(gè)變量,和 is T variable 寫(xiě)法格式(聲明模式)一致,但是,注意內(nèi)聯(lián)的這個(gè)變了和原始變量的類型和可空語(yǔ)義的不同:被匹配的變量(原始變量)是可空的,但是內(nèi)聯(lián)的后者這個(gè)變量是一定不空的。

C# 是允許變量聲明的內(nèi)聯(lián)作為模式匹配的一部分的。這里僅用空屬性模式介紹了內(nèi)聯(lián)變量的寫(xiě)法,但你要知道的是,內(nèi)聯(lián)變量可用在任何情況下的屬性模式。

4、盡量不要讓本來(lái)就不為 null 的表達(dá)式使用屬性模式

可以發(fā)現(xiàn),is 的左邊其實(shí)可以為一個(gè)表達(dá)式。因此下面的代碼是合法的:

不過(guò),這種寫(xiě)法具有副作用。is 的左邊一定是一個(gè)不為 null 的表達(dá)式,那么我們就沒(méi)有理由使用 is { } 來(lái)進(jìn)行模式匹配。因?yàn)檫@樣會(huì)導(dǎo)致編譯器生成不必要的判空代碼。

因此,為了避免這樣的寫(xiě)法出現(xiàn),我們可以改成 var 模式,或者是直接定義一個(gè)新的變量來(lái)進(jìn)行賦值。

請(qǐng)注意。這里所說(shuō)的屬性模式不單單只是空屬性模式。在里面帶別的屬性使用 var 模式的話,也是不必要的寫(xiě)法。

這種寫(xiě)法看似是在直接使用大括號(hào)語(yǔ)法來(lái)同時(shí)獲取兩個(gè)屬性的數(shù)值,但是如果 Student 是引用類型的話,屬性模式的大括號(hào)本身會(huì)讓編譯器自動(dòng)生成判空代碼,于是這樣的代碼等價(jià)于 !ReferenceEquals(student, null) && student.Name is var name && student.Age is var age。是的,它會(huì)做一次判斷 null 的冗余操作。

如果你需要對(duì)多個(gè)這樣的屬性一齊取值的話,我建議你使用值元組來(lái)進(jìn)行賦值:

用這樣的語(yǔ)法來(lái)代替原來(lái)的寫(xiě)法。這樣的賦值和原始的賦值的期望結(jié)果是一致的,但代碼里也不會(huì)多出冗余的判空。

5、可空值類型模式匹配是匹配的內(nèi)部數(shù)值

判別對(duì)象是否為空,我們可以使用 is null 來(lái)完成,因此不空就使用 !(obj is null) 就可以了;與此同時(shí),由于空屬性模式也可以完成相同的行為,因此這樣的代碼也可以寫(xiě)成 obj is { };對(duì)于可空值類型來(lái)說(shuō),我們還可以使用 HasValue 屬性來(lái)完成:obj.HasValue。

但是,可空值類型在模式匹配里是當(dāng)成值類型來(lái)假設(shè)的——它可能含有數(shù)值,那么數(shù)值直接拿出來(lái)即可;如果不含有數(shù)值,返回 null 就是判斷模式的結(jié)果。而這里的 HasValue 是對(duì)所有可空值類型都具備的一個(gè)獨(dú)特特性。但是在模式匹配里,你無(wú)法這么寫(xiě)代碼:

比如屬性模式,我們想要直接使用 HasValue 屬性來(lái)完成屬性模式匹配,這樣的語(yǔ)法是錯(cuò)誤的。因?yàn)榫幾g器會(huì)假設(shè) nullableValueObject 在模式匹配里是按數(shù)值進(jìn)行判斷的,即使它本身是可空值類型,但在模式匹配里它是被視為一個(gè)包含 null 的普通數(shù)值類型。比如說(shuō) aint? 類型,那么 a is { HasValue: _ } 就是錯(cuò)誤寫(xiě)法:因?yàn)?a 會(huì)被視為包含 null 的普通 int 類型,而不會(huì)被當(dāng)成 int? 類型(即 Nullable<int> 類型)。這個(gè)意義在于,由于它進(jìn)行模式匹配并不會(huì)被視為可空值類型,因此你無(wú)法使用 { HasValue: _ } 類似的模式來(lái)獲取其結(jié)果。

如果確實(shí)要獲取可空值類型的內(nèi)部數(shù)據(jù),你應(yīng)該寫(xiě) a is { } va.HasValue && a.Value is var v,而不是 a is { HasValue: _, Value: var v }。

6、用屬性模式解構(gòu)值類型對(duì)象

是的,C# 編譯器確保了我們的操作完全只包含解構(gòu)行為的時(shí)候,是可以不做判斷即可使用這些變量的。舉個(gè)例子。

它不依賴于你的解構(gòu)函數(shù):只要對(duì)象具有該屬性數(shù)值且包含 get 訪問(wèn)器可以用于取值操作,這個(gè)屬性就可以用來(lái)作為屬性模式解構(gòu)操作的一部分。這種解構(gòu)形式和之前學(xué)到的解構(gòu)函數(shù)的解構(gòu)模式不同,這里用的是屬性模式的方式獲取,因此稱為屬性模式解構(gòu)(Property-pattern-styled Deconstruction)。

另外,上面用到了棄元符號(hào)。因?yàn)?is 表達(dá)式不可單獨(dú)使用,它必須返回?cái)?shù)值給變量調(diào)用。如果你確實(shí)不使用結(jié)果變量(實(shí)際上這個(gè)解構(gòu)行為根本就不可能失敗,所以上面這樣的 is 表達(dá)式永遠(yuǎn)返回 true)賦值給等號(hào)左側(cè)的話,只需要寫(xiě)棄元符號(hào)即可,它等價(jià)于這樣:

又或者是

等等寫(xiě)法。

另外,這樣的解構(gòu)風(fēng)格允許你包含棄元模式嵌套在屬性模式之中。但凡右側(cè) 100% 是成功的解構(gòu)操作的話,你怎么寫(xiě)模式匹配都可以:

這些都是編譯器允許的寫(xiě)法。這種就是帶有遞歸使用的解構(gòu),它也是編譯器允許的,因?yàn)檫@樣的解構(gòu)操作肯定是成功的。否則,由于可能失敗,所以帶有別的模式匹配的話,你可能就得用 if 來(lái)判斷一下才知道是否模式匹配成功了。

這樣的話,由于 A 屬性判斷了數(shù)值,所以可能解構(gòu)操作不成功,這種場(chǎng)合你只能使用 if,而且不能簡(jiǎn)化成上面屬性模式風(fēng)格的解構(gòu)的樣式。順帶一說(shuō),_ = a is pattern 表達(dá)式的 _ 不是模式匹配,它只是表示變量我們不使用了。

7、遞歸模式Ⅰ:屬性模式遞歸

C# 強(qiáng)大的地方在于,語(yǔ)法很靈活,這樣我們寫(xiě)代碼可以不用唯一的一條道路去實(shí)現(xiàn)。比如前面的解構(gòu)模式。(x: var x, y: var y) 里又是一個(gè) var 模式的變量聲明。所以,正是因?yàn)檫@樣,我們學(xué) C# 就不必學(xué)得那么痛苦。

C# 的屬性模式是 C# 一大秀兒語(yǔ)法。它允許遞歸使用屬性模式進(jìn)行判斷。假設(shè)我有這么一個(gè)對(duì)象:

這個(gè)對(duì)象是表示一個(gè)人的基本數(shù)據(jù)信息,比如名字啊、年齡啥的,當(dāng)然也存儲(chǔ)了 ta 的父母的實(shí)例的引用。

其中,我們假設(shè) Gender 類型是個(gè)暫時(shí)只包含 MaleFemale 倆字段的枚舉類型。

Person? 語(yǔ)法表示 Person 這個(gè)引用類型具有和值類型類似的語(yǔ)法:這個(gè)屬性信息可為 null。反之,如果沒(méi)有 ? 標(biāo)記的類型,這個(gè)成員的數(shù)值就不能為 null。這個(gè)語(yǔ)法是 C# 8 里的,這里為了體現(xiàn)出判斷用法,故意寫(xiě)上了 ? 來(lái)表達(dá)為 null、更顯眼一點(diǎn);另外,這里故意取可為 null 的寫(xiě)法,還有一個(gè)目的,是為了體現(xiàn)一會(huì)兒模式匹配的語(yǔ)義,所以請(qǐng)不要和現(xiàn)實(shí)世界進(jìn)行對(duì)比或者對(duì)號(hào)入座。

假如,我們要判斷是否某個(gè)人的姓名是“張三”、年齡 24,他爸叫“張二”、而他的媽媽則叫“李四”。如果要判斷這個(gè)對(duì)象的具體信息,我們可以這么寫(xiě)代碼:

注意這里的模式匹配寫(xiě)法。前面模式匹配就用的是大括號(hào),因此我們可以對(duì)對(duì)象的內(nèi)部信息繼續(xù)作判斷。比如 FatherMother 屬性又是一個(gè) Person 類型的對(duì)象,因此我們還可以接續(xù)一個(gè)大括號(hào)對(duì) FatherMother 的值的具體內(nèi)容繼續(xù)進(jìn)行判斷。

一定要注意。FatherMother 屬性是可能為 null 的。當(dāng) Father 屬性的數(shù)值本身就是 null 的時(shí)候,那么顯然就不存在 Name: "Zhang 'er" 的判斷行為了:因?yàn)?null 值本身就無(wú)法繼續(xù)判斷內(nèi)部數(shù)據(jù)了。因此,在 Fathernull 的時(shí)候,模式匹配結(jié)果一定是 false。當(dāng)且僅當(dāng)整個(gè)判斷的邏輯全都匹配,if 條件才成立。

順帶給大家看下,C# 的模式匹配到底多有魅力:給大家展示一個(gè)我之前寫(xiě)過(guò)的一段代碼,用到了這里的模式匹配。

這里,這么一大坨都是遞歸的模式匹配。正好這體現(xiàn)出了模式匹配的魅力。

8、遞歸模式Ⅱ:對(duì)位模式和屬性模式是可以放在一起的

C# 的屬性模式具有和對(duì)位模式完全一致的判斷行為,因此 C# 就把對(duì)位模式和屬性模式在語(yǔ)義分析上放在了一起。假設(shè)我有一個(gè) Point 類型,包含 XY 屬性(它們通過(guò)解構(gòu)函數(shù)解構(gòu)為 xy 兩個(gè)參數(shù)),并且包含 Area 屬性表示當(dāng)前點(diǎn)到坐標(biāo)原點(diǎn)構(gòu)成的矩形的面積。

這里不是講數(shù)學(xué),我只是告訴你如何并用兩個(gè)模式。

可以看到,我們直接在 (x: 10, y: 30) 這個(gè)對(duì)位模式后加上了 { Area: _ } 屬性模式。在 C# 里,對(duì)位模式和屬性模式均可以用于遞歸使用(比如假設(shè)一個(gè)對(duì)位模式的成員是可以繼續(xù)通過(guò)別的模式進(jìn)行匹配的,那么這個(gè)成員就可以繼續(xù)遞歸地進(jìn)行模式的判斷),同時(shí)屬性模式也是如此,前文已經(jīng)說(shuō)過(guò)了。因此,C# 把對(duì)位模式和屬性模式統(tǒng)稱遞歸模式(Recursive Pattern)。換句話說(shuō),在概念上來(lái)講,你可以同時(shí)使用對(duì)位模式和屬性模式的兩種不同模式的判別,并放在一起,這個(gè)整體叫做遞歸模式。

但請(qǐng)注意,必須是先對(duì)位模式,后屬性模式的順序。寫(xiě)反了是不行的。


C# 屬性模式的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
呼玛县| 中江县| 江城| 增城市| 清苑县| 安国市| 都江堰市| 丰县| 高唐县| 大田县| 钟山县| 连平县| 大宁县| 新疆| 闻喜县| 镇原县| 连城县| 青龙| 西平县| 故城县| 沂南县| 察哈| 陇川县| 曲沃县| 公安县| 中江县| 阿拉善右旗| 夏邑县| 绍兴市| 涪陵区| 武定县| 棋牌| 舞钢市| 禄劝| 孟州市| 监利县| 高青县| 莱州市| 上虞市| 永清县| 靖边县|