Visual Basic 中的泛型型別

更新:2007 年 11 月

「泛型型別」是單一程式設計項目,適用於針對多種資料型別執行相同的功能。當您在定義泛型類別或程序時,不需要針對您想要執行該功能的每種資料型別定義不同的版本。

以下使用含有可更換頭的螺絲起子做比喻。您會先檢查想要轉動的螺絲,然後針對該螺絲 (一字形、十字形或星字形) 選取正確的螺絲起子頭。一旦您將正確的螺絲起子頭插入螺絲起子柄後,就可以用該螺絲起子執行相同的功能,也就是轉動螺絲。

設定為泛型工具的螺絲起子

一組泛用螺絲起子工具組的圖表

當您定義泛型型別後,您就會以一或多個資料型別進行參數化。這樣可讓使用中的程式碼根據需求調整資料型別。您的程式碼可以從泛型項目宣告數種不同的程式設計項目,而每個項目都可以作用於不同的資料型別集。但是不論宣告的項目是使用哪種資料型別,都會執行相同的邏輯。

例如,您可能想要建立和使用可在特定資料型別 (例如 String) 上運作的佇列類別。您可以從 System.Collections.Generic.Queue<T> 宣告此種類別,如下列範例所示。

Public stringQ As New System.Collections.Generic.Queue(Of String)

您現在可以使用 stringQ,以獨佔模式與 String 值一起運作。因為 stringQ 是 String 特有的,而不是通用於 Object 值,因此您沒有晚期繫結或型別轉換。這可以節省執行時間並且減少執行階段錯誤。

如需使用泛型型別的詳細資訊,請參閱 HOW TO:使用泛型類別

泛型類別的範例

下列範例會顯示泛型類別的基本架構定義。

Public Class classHolder(Of t)
    Public Sub processNewItem(ByVal newItem As t)
        Dim tempItem As t
        ' Insert code that processes an item of data type t.
    End Sub
End Class

在先前的基本架構中,t 為「型別參數」,也就是您在宣告類別時所提供之資料型別的替代符號 (Placeholder)。您可以在程式碼的其他地方,宣告各種的 classHolder 版本,方法便是提供 t 的各種資料型別。以下範例顯示兩個此類宣告。

Public integerClass As New classHolder(Of Integer)
Friend stringClass As New classHolder(Of String)

先前的陳述式會宣告「建構的類別」,其中特定型別會取代型別參數。這項取代會遍及建構之類別內的程式碼。下列範例會顯示 processNewItem 程序在 integerClass 中的外觀。

Public Sub processNewItem(ByVal newItem As Integer)
    Dim tempItem As Integer
    ' Inserted code now processes an Integer item.
End Sub

如需更完整的範例,請參閱 HOW TO:定義可以在不同資料型別上提供完全相同功能的類別

合格的程式設計項目

您可以定義並使用泛型類別、結構、介面、程序和委派 (Delegate)。請注意,.NET Framework 會定義數個代表通用泛型項目的泛型類別、結構和介面。System.Collections.Generic 命名空間 (Namespace) 會提供字典、清單、佇列和堆疊。在定義自己的泛型項目之前,請查看它是否已存在 System.Collections.Generic 中。

程序並非型別,但您可以定義和使用泛型程序。請參閱 Visual Basic 中的泛型程序

泛型型別的優點

泛型型別可以做為宣告數個不同程式設計項目的基礎,而每個項目會在特定的資料型別上運作。泛型型別的替代型別如下:

  1. 在 Object 資料型別上運作的單一型別。

  2. 一組「特定型別」的型別版本,每個版本都會個別進行編碼並於某一個特定的資料型別上運作,例如 String、Integer 或使用者定義的型別 (如 customer)。

泛型型別具有優於這些替代型別的下列優點:

  • 型別安全 (Type Safety):泛型型別會強制進行編譯時期型別檢查。以 Object 為基礎的型別會接受任何資料型別,而且您必須撰寫程式碼以檢查輸入資料型別是否可接受。利用泛型型別,編譯器 (Compiler) 可以在執行階段前攔截不符的型別。

  • 效能。:因為每個泛型型別都會針對某一種資料型別進行特製化,所以泛型型別不必進行資料的「Box」和「Unbox」處理。根據 Object 的作業都必須進行輸入資料型別的 Box 處理,將這些資料型別轉換為 Object,並針對預定輸出的資料進行 Unbox 處理。Box 和 Unbox 處理都會降低效能。

    以 Object 為基礎的型別也屬於晚期繫結的型別,這表示在執行階段存取這些型別的成員時,還需要額外的程式碼。這也會降低效能。

  • 程式碼合併:泛型型別中的程式碼只能夠定義一次。一組型別的特定型別版本必須在每個版本中複寫相同的程式碼,唯一的差異在於該版本的特定資料型別。就泛型型別而言,特定型別的版本都是從原始泛型型別產生。

  • 重複使用程式碼:未相依於特殊資料型別的程式碼可以重複使用於各種資料型別 (如果是泛型型別的話)。通常甚至可以重複使用於您原先未預期的資料型別。

  • IDE 支援:當您使用從泛型型別宣告之建構的型別時,整合式開發環境 (IDE) 便可以於開發程式碼時給予更多支援。例如,IntelliSense™ 可以針對建構函式或方法的引數,顯示特定型別的選項。

  • 泛型演算法:與型別無關的抽象演算法可以做為良好的泛型型別。例如,使用 IComparable 介面排序項目的泛型程序,可以用於實作 IComparable 的任何資料型別。

條件約束

雖然泛型型別定義中的程式碼應該盡可能與型別無關,但您可能會要求提供給泛型型別的任何資料型別具有某項功能。例如,如果您想藉由比較兩個項目來達到排序或定序的目的,這兩個項目的資料型別就必須實作 IComparable 介面。您可以將「條件約束」加入至型別參數,以強制這項要求。

條件約束範例

下列範例會顯示類別的基本架構定義,該類別具有要求型別引數實作 IComparable 的條件約束。

Public Class itemManager(Of t As IComparable)
    ' Insert code that defines class members.
End Class

如果後續的程式碼嘗試從提供未實作 IComparable 之型別的 itemManager 建構類別,則編譯器會發出錯誤信號。

條件約束型別

您的條件約束可以利用任意組合指定下列需求:

  • 型別引數必須實作一或多個介面。

  • 型別引數必須為某個類別的型別,或繼承自至多一個類別。

  • 型別引數必須公開 (Expose) 無參數的建構函式,此建構函式可供據此建立物件的程式碼存取。

  • 型別引數必須是「參考型別」(Reference Type),或必須是「實值型別」(Value Type)。

如果您需要強制一個以上的要求,可以在大括號 ({ }) 內使用逗號分隔的「條件約束清單」。如需要求可存取的建構函式,可以在清單中包含 New (Visual Basic) 關鍵字。如需要求參考型別,您可以包含 Class (Visual Basic) 關鍵字。而若要要求實值型別,則可以包含 Structure (Visual Basic) 關鍵字。

如需條件約束的詳細資訊,請參閱型別清單

多重條件約束的範例

下列範例會顯示泛型類別的基本架構定義,此類別具有型別參數的條件約束清單。在建立此類別之執行個體的程式碼中,型別引數必須是參考型別,且必須實作 IComparableIDisposable 介面,並公開可存取的無參數建構函式。

Public Class thisClass(Of t As {IComparable, IDisposable, Class, New})
    ' Insert code that defines class members.
End Class

重要詞彙

泛型型別會引入並使用下列詞彙:

  • 泛型型別:類別、結構、介面、程序或委派的定義,您會在進行宣告時提供至少一個資料型別。

  • 型別參數:在泛型型別定義中,您在宣告型別時所提供之資料型別的替代符號 (Placeholder)。

  • 型別引數:從泛型型別宣告建構的型別時,取代型別參數的特定資料型別。

  • 條件約束:型別參數的條件,會限制您可以提供的型別引數。條件約束可以要求型別引數必須實作特定介面、本身必須為或是必須繼承自特定類別、具有可存取的無參數建構函式,或為參考型別或實值型別。您可以結合這些條件約束,但最多只能指定一個類別。

  • 建構的型別:藉由提供型別參數的型別引數,從泛型型別宣告的類別、結構、介面、程序或委派。

請參閱

工作

資料型別疑難排解

概念

Visual Basic 中的資料型別

型別字元

實值型別和參考型別

參考

資料型別摘要 (Visual Basic)

Of

As

Object 資料型別

其他資源

資料型別實作

Visual Basic 中的型別轉換