第 90 講:C# 3 之對象初始化器
繼前文介紹的一些有關(guān)數(shù)組初始化器的語法更新,我們來說兩種初始化器的語法優(yōu)化。今天要說的是第一種初始化器:對象初始化器(Object Initializer)。
Part 1 對象初始化器的概念
在早期,我們要對一個(gè)對象的數(shù)據(jù)進(jìn)行賦值,我們必須在實(shí)例化后,跟著一堆屬性和字段賦值的語句,比如這樣:
這樣且不說寫沒寫對,語法看著也不好,可讀性也不高。因?yàn)檫@樣的初始化賦值過程本身就應(yīng)該是放在一起的,而這樣分行書寫進(jìn)行賦值的過程是可以隨意在中間任何位置插入別的代碼的。這樣就斷開了賦值的過程,導(dǎo)致我們很難再次確認(rèn)語句的賦值完整性。
C# 3 開始引入一個(gè)全新的概念:對象初始化器。對象初始化器的語法是采用類似數(shù)組初始化器的語法,使用大括號(hào)來完成。不過,因?yàn)閷ο笫强梢宰远x賦值的屬性或者字段的,因此對象初始化器里需要你指定賦值的屬性或字段,然后是對應(yīng)數(shù)值。每一個(gè)賦值語句之間使用逗號(hào) ,
隔開。注意隔開用的是逗號(hào) ,
而不是分號(hào) ;
了。
請注意賦值的語法。這個(gè)對象初始化器是直接跟在 new
實(shí)例化語句的后面,直接去掉了分號(hào)(或者說把分號(hào)的位置后置到對象初始化器的后面去了)。其中我們把這個(gè) new T() { ... }
的語句稱為實(shí)例化表達(dá)式,而 new T()
是傳統(tǒng)的實(shí)例化表達(dá)式的部分,而多出來的 { ... }
語法,是 C# 3 的新概念——對象初始化器了。
Part 2 使用規(guī)則和限制
我們可以從這個(gè)語法看出,賦值的屬性和字段都是可以通過這樣的過程來完成,不過我們可以從命名上看出,Age
、Name
和 Gender
都是首字母大寫的詞語,這意味著它們大概率應(yīng)該是一個(gè)屬性的名字,如果是字段的話,我們都按照規(guī)則和約定使用了下劃線開頭的駝峰命名法了,就不長這樣了。雖然例子是這么介紹的,好像只用了屬性,但是實(shí)際上字段也可以。
2-1 賦值可訪問性的限制
問題是,總不能啥字段都行吧?假設(shè)我一個(gè) Ellipse
(橢圓類型)要賦值半長軸和半短軸的數(shù)值,但實(shí)際上它具有三個(gè)屬性:
對它包含了 Area
屬性表示和計(jì)算該橢圓的面積。顯然這個(gè) Area
就非常不適合使用對象初始化器提前給 Area
這個(gè)壓根沒有賦值器的屬性進(jìn)行提前賦值。
那么,對象初始化器的賦值過程有什么限制嗎?
很簡單的一個(gè)規(guī)則:在使用初始化器的時(shí)候,起碼得保證賦值是可以操作的。所謂的“可以操作”,對于屬性來說,就是能在這個(gè)時(shí)候看得到它的 setter;對于字段來說,就是能在當(dāng)前寫代碼的地方看得到這個(gè)字段。
顯然,Ellipse
類型是 public
的,那么不擔(dān)心這個(gè)類型在某個(gè)位置看不到;再看字段。字段是私有的,所以你無法使用初始化器直接對 _a
和 _b
字段賦值;而屬性里 A
和 B
都有可以訪問的 setter,所以可以使用 A
和 B
來進(jìn)行屬性的賦值;而 Area
屬性沒有 setter,就談不上賦值過程和功能了。所以:
可以從注釋看出,_a = 10
部分、_b = 10
部分和 Area = 60
部分都是錯(cuò)誤的賦值過程。
2-2 允許結(jié)尾處多余的逗號(hào)
注意 B = 10
后跟了一個(gè)無意義的逗號(hào)。這是允許的,因?yàn)檫@個(gè)逗號(hào)在末尾,所以它有沒有都行。
2-3 允許省略無參構(gòu)造器的小括號(hào)
為了繼續(xù)簡化代碼的使用,如果配上了對象初始化器的實(shí)例化表達(dá)式,無參構(gòu)造器的小括號(hào)是可以不要的。當(dāng)然,僅限是無參構(gòu)造器:
new Ellipse() { ... }
被簡寫為了 new Ellipse { ... }
不過,寫不寫在一排取決于你的代碼風(fēng)格和書寫習(xí)慣了。
2-4 允許嵌套使用對象初始化器
我們還是用之前的學(xué)生類型 Student
來舉例。這次我們多追加一個(gè)屬性叫 Deskmate
表示這個(gè)學(xué)生的同桌是誰:
Student
Deskmate
屬性等待我們賦值??蓡栴}就在于,我的同桌的同桌應(yīng)該還是我自己。比較尷尬的是,我現(xiàn)在是對象的初始化器里的語法,它表示對象正在初始化
我是想這么干:

但,對不對呢?當(dāng)然不對。我這里 student
變量都還沒初始化好呢,我當(dāng)然不能直接引用給賦值過去。所以,我只能寫在后面??梢钥吹酱a的最后一行,我們在初始化器語法對應(yīng)的語句的后面補(bǔ)充了一句。對于這種情況,我們只能這么賦值。
Part 3 總結(jié)
所以,總的來說,對象初始化器就是這么一種語法,它把賦值過程整合到了一起,更加規(guī)范化。
因此本文結(jié)束了。下一講我們繼續(xù)探討另外一種初始化器:集合初始化器(Collection Initializer)。