首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

LINQ 演進歷程與對 C# 設計的影響(四):匿名類型與隱含型別區域變數

     編輯:關於C語言

匿名類型

若想繼續使用現有語法回傳名稱與地址,很快會面臨問題:不存在僅包含 Name 與 Address 的類型。雖仍可撰寫查詢,但必須引入該類型:

class CustomerTuple
{
    public string Name;
    public string Address;
    public CustomerTuple(string name, string address)
    {
        this.Name = name;
        this.Address = address;
    }
}

然後才能使用該類型,即此處的 CustomerTuple,產生查詢結果:

IEnumerable locals = customers.Where(c => c.ZipCode == 91822).Select(c => new CustomerTuple(c.Name, c.Address));

這確實像許多用於投影欄位子集的樣板代碼。且往往不清楚如何命名此類型。CustomerTuple 真的是好名稱嗎?若投影 Name 與 Age 又該如何命名?也可叫 CustomerTuple。問題在於我們擁有樣板代碼,且似乎無法為建立的類型找到恰當名稱。此外可能需要許多不同類型,管理這些類型很快會成為棘手問題。

這正是匿名類型要解決的問題。此功能主要允許在無需指定名稱情況下建立結構化類型。若使用匿名類型重寫上述查詢:

locals = customers.Where(c => c.ZipCode == 91822)
                .Select(c => new { c.Name, c.Address });

此代碼會隱含建立一個擁有 Name 與 Address 欄位的類型:

class
{
    public string Name;
    public string Address;
}

此類型無法透過名稱參考,因為它沒有名稱。建立匿名類型時,可顯式宣告欄位名稱。例如,若建立的欄位衍生自複雜運算式,或純粹不需要名稱,可更改名稱:

locals = customers.Where(c => c.ZipCode == 91822)
                .Select(c => new { FullName = c.FirstName + " " + c.LastName, HomeAddress = c.Address });

此情形下,產生的類型擁有 FullName 與 HomeAddress 欄位。

這樣我們又向理想世界邁進一步,但仍存一問題。您會發現,我在任何使用匿名類型處都策略性省略區域變數型別。顯然無法宣告匿名類型名稱,那我們如何使用它們?

隱含型別區域變數

另一語言功能稱為隱含型別區域變數 (簡稱 var),負責指示編譯器推斷區域變數型別。例如:

var integer = 1;

此例中 integer 擁有 int 型別。請務必明白,這仍屬強型別。動態語言中 integer 型別可稍後變更。為說明此點,以下代碼無法成功編譯:

var integer = 1;
integer = "hello";

C# 編譯器將回報第二行錯誤,指出無法將字串隱含轉換為 int。

在上述查詢範例中,現在可撰寫完整指派:

var locals =
    customers
    .Where(c => c.ZipCode == 91822)
    .Select(c => new { FullName = c.FirstName + " " + c.LastName, HomeAddress = c.Address });

區域變數型別最終成為 IEnumerable<?>,其中「?」為無法撰寫的型別名稱 (因為它是匿名的)。

隱含型別區域變數僅為:方法內部的區域變數。它們無法超出方法、屬性、索引子或其他區塊邊界,因該型別無法顯式宣告,且「var」對欄位或參數型別而言是非法的。

事實證明,隱含型別區域變數在查詢情境外非常方便。例如,有助於簡化複雜泛型實例化:

var customerListLookup = new Dictionary<string, List<Customer>>();

現在我們的查詢取得良好進展;我們已接近理想語法,且使用通用語言功能達成。

有趣的是,隨著越來越多人使用此語法,經常出現允許投影超越方法邊界的需求。如前所見,這可行,只要從 Select 內部呼叫物件建構函式建構物件即可。但若沒有準確接受所需設定值的建構函式,會發生什麼?

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved