這表明,編譯器在編譯的時候,已經正確地推斷了每個變量的類 型,並將其嵌入到了程序集的元數據中。
這裡有兩個限制,一是具有隱 式類型的聲明只能作用在局部變量上,二是這種聲明必須有初始化器(即等號和 後面的表達式)。如果我們企圖在一個類中聲明一個具有隱式類型的域,就會出 現一個編譯錯誤:Invalid token ’var’ in class, struct, or interface member declaration;而如果聲明中沒有出現初始化器,則會導致另 外一個編譯錯誤:’=’ expected。
除了局部變量外,作用 域為一個塊的數組也可以運用具有隱式類型的聲明,例如:
var ia = new [] { 1, 2, 3, 4, 5 }; // int[]
var da = new [] { 1.1, 2, 3, 4, 5 }; // double[]
var sa = new [] { "Hello", "World" }; // string[]
Console.WriteLine("Type of array <ia>: {0}", ia.GetType());
Console.WriteLine ("Type of array <da>: {0}", da.GetType());
Console.WriteLine("Type of array <sa>: {0}", sa.GetType());
在上面例子的數組聲明中,在運算符new和表示 數組聲明的一對方括號之間省略了類型名字,但這在C# 3.0中仍然是符合語法規 則的。編譯器會通過成員列表中的值的類型來推斷數組的類型。編譯並運行上面 的例子,會得到如下的輸出:
Type of array <ia>: System.Int32[]
Type of array <da>: System.Double[]
Type of array <sa>: System.String[]
除了和具有隱 式類型的局部變量具有相同的約束外,具有隱式類型的數組還有必須尊從這樣一 個規則,即成員列表中的所有值必須是兼容的。也就是說,成員列表中必須存在 這樣一個值,使得其他值可以隱式地轉換為該值的類型。因此,下面的聲明是不 符合語法規則的:
var aa = new [] { 1, "Hello", 2.0, "World" };
如果試圖編譯上面的代碼,會得到 一個編譯錯誤:No array type can be inferred from the initializers。這 是因為編譯器無法根據成員列表中的值來推斷數組的類型。
實際上,盡 管具有隱式類型的聲明使得傳統聲明的編寫方法更加便利,然而引入這種聲明方 式的真正目的並不在於此,而是為了使局部變量和數組能夠訪問這樣一個新的語 言構造:匿名類型。
對象和集合初始化器
1、對象初始化器
在C# 3.0出現之前,如果想在構造一個對象的時候對其成員進行初始化 ,只有通過調用帶參數的構造器來完成。如果一個類型僅提供了無參構造器(默 認構造器)或構造器接受的參數和對象的公共屬性沒有太大關系,對對象的初始 化就只能通過兩個步驟來完成:首先是聲明一個對象,然後對其公共屬性進行賦 值。
C# 3.0引入了對象初始化器的語言構造,可以在聲明對象的時候對 其公共可讀寫屬性進行賦值。例如我們有這樣一個類型:
class Book
{
private string m_name;
private string m_isbn;
private float m_price;
public string Name { get { return m_name; } set { m_name = value; } }
public string Isbn { get { return m_isbn; } set { m_isbn = value; } }
public float Price { get { return m_price; } set { m_price = value; } }
}
那麼,我們就可以用下面的簡單方式來初始化Book類的對象:
var firstBook = new Book
{
Name = "The First Sample Book",
Isbn = "1-111-11111-1",
Price = 88.0f
};
var secondBook = new Book
{
Name = "The Second Sample Book",
Price = 25.0f,
Isbn = "2-222-22222-2"
};
也就是說,只要 在對象聲明語句的末尾添加一對花括號,並在其中對每個屬性進行賦值即可。並 且我們可以看到,第二個聲明中對屬性的賦值語句的順序與Book類中屬性定義的 順序並不相同,但這完全是符合語法規則的,只要明確指定了要賦值的屬性名字 即可。另外,也可以只對一部的屬性進行賦值,如只對Isbn進行賦值,而在稍後 通過查詢等手段為Name和Price屬性賦值。甚至可以保留一個空的屬性賦值列表 ,這時每個屬性都被賦以相應類型的默認值。
實際上,對象初始化器完 成的工作還是我們以前要完成的那兩步,只不過由編譯器代勞了,例如上面對 firstBook的聲明將被編譯器翻譯為形如下面的代碼,之後才進行進一步的編譯 :
var firstBook = new Book;
firstBook.Name = "The First Sample Book";
firstBook.Isbn = "1-111- 11111-1";
firstBook.Price = 88.0f;