[譯]Visual Basic 2005在語言上的增強(四)泛型

BCL(Base Class Library,涕淌注)現在提供了System.Collections.Generic的命名空間,其中包括了不少定義了範型集合的類。之所以稱之爲“泛型”,是因爲在定義的時候,你只是爲其包含的對象指派了一個類型佔位符,而不是將它定義爲某個確定的類型。你只有在創建該集合的某個實例時,纔會給它存儲的對象指定一個特定的類型。

泛型極大地節省了我們的時間。如果你曾經創建過自定義集合,你就會體會到箇中要添加多少的代碼了。Visual Basic中的泛型可以讓你只用一行的代碼量,就創建出一個自定義集合的匹配物。你再也不必費神爲你想存儲的每種類型的對象創建各自獨立的集合了。你僅需提供在你初始化一個泛型集合時你喜歡的某個類型。

想要了解泛型是如何工作的,最簡單的方式是一起來看一個例子。假設你有一個簡易的Customer類,它包含了兩個公開的屬性(爲了簡約,在下面被定義成了公共變量):
Public Class Customer
    Public Name As String
    Public CreditLimit As Decimal
    Public Sub New(ByVal CustomerName As String, ByVal CustCreditLimit As Decimal)
        Name = CustomerName
        CreditLimit = CustCreditLimit
    End Sub
End Class

你可以像下面那樣聲明一系列的Customers,其中使用到了泛型集合的List類:
Dim Customers As New System.Collections.Generic.List(Of Customer)

就僅僅這麼一行代碼,你就已經聲明瞭一個僅能存儲Customer類型的強類型列表,並且得到了關於其包含的Customer對象的完整的智能感知。你也同樣可以創建一系列的Product或是Order對象,高效率地創建一套自定義集合,而無須爲所有類型填寫各自的代碼。你可以像下面這樣寫:
Dim custA As New Customer("CustA", 1000)
Customers.Add(custA)
Dim custB As New Customer("CustB", 2000)
Customers.Add(custB)
For Each c As Customer In Customers
    MessageBox.Show("Customer: " & c.Name & ", limit: " & c.CreditLimit)
Next
'編譯錯誤:Product類型無法轉換成Customer類型
Dim prodA As New Product("ProdA", CDec(29.95))
Customers.Add(prodA)

泛型集合的執行效率也毫不遜色,因爲存儲的對象是強類型的,而不是內在地被指定爲Object類型。

在System.Collections.Generic命名空間下,還能找到其他的範型集合。譬如,Dictionary(Of K, V)集合允許你爲關鍵字和值限定類型。LinkedList(Of T)及Stack(Of T)泛型集合的作用方式和普通的鏈表和堆棧無甚差別,只是你可以指定它們要存儲的對象類型而已。

你可以使用新的泛型聲明句法來創建你自己的泛型。我們來看看一個Comparer類,這個類可以用來比較兩個不同類型的對象:
Public Class Comparer(Of itemType)
    '...
End Class

你可以通過用逗號隔開的列表方式定義多重類型的佔位符。你也可以定義一個約束條件來限制哪些類能在泛型初始化後提供給該泛型。
Public Class Comparer(Of itemType As IComparable)
    '...
End Class

這個約束條件確保了Comparer(Of T)的實例只能通過那些實現了IComparable接口的類創建。多重約束條件也一樣適用於類的聲明。

作爲一個示例,我們再來看一下這個擴充了的、實現了IComparable接口的Customer類:
Public Class Customer
    Implements IComparable

    Public Name As String
    Public CreditLimit As Decimal
   
    Public Sub New(ByVal CustomerName As String, ByVal CustCreditLimit As Decimal)
        Name = CustomerName
        CreditLimit = CustCreditLimit
    End Sub

    Public Function CompareTo(ByVal obj As Object) As Integer _
        Implements
IComparable.CompareTo
        Dim c As Customer = CType(obj, Customer)
        If CreditLimit > c.CreditLimit Then Return 1
        If CreditLimit < c.CreditLimit Then Return -1
        Return 0
    End Function

End Class

類似地,Product類也可以被實現,不過CompareTo函數比較的是產品的價格而不是客戶的存款限額:
Public Class Product
    Implements IComparable
    Public Name As String
    Public Price As Decimal
    Public Sub New(...)...
    Public Function CompareTo(...)...
End Class

Comparer類提供了泛型比較操作:
Public Class Comparer(Of itemType As IComparable)
    Public Function GetLargest(ByVal Item1 As itemType, _
                                              ByVal Item2 As itemType) As itemType
        Dim i As Integer = Item1.CompareTo(Item2)
        If i > 0 Then Return Item1
        If i < 0 Then Return Item2
        Return Nothing
    End Function
End Class

你現在可以用不同類型的對象來實例化Comparers(這裏用複數沒有別的意思,只是說你可以實例化多個Comparer實例,涕淌注)了:
Dim pc As New Comparer(Of Product)
Dim prod1 As New Product("LittleOne", 10)
Dim prod2 As New Product("BigOne", 100)
Dim lp As Product = pc.GetLargest(prod1, prod2)
MessageBox.Show("The more expensive product is: " & lp.Name)
Dim cc As New Comparer(Of Customer)
Dim cust1 As New Customer("SmallCo", 1000)
Dim cust2 As New Customer("LargeCo", 5000)
Dim lc As Customer = cc.GetLargest(cust1, cust2)
MessageBox.Show("The customer with a higher limit is: " & lc.Name)

若是沒有了泛型,你就不得不爲任何一種你想用來比較的對象類型分別定義一個比較類(比如說,ProductComparerOrderComparer)。

在不少常見的場合,泛型都在很大程度上減輕了你的代碼負擔。想象一下吧,當你有着式樣繁多的類,而它們僅僅在操作的對象類型上有所差別時,使用泛型會是多麼利便的事。


@以下附上原文供大家參考@

Generics

The BCL now provides the System.Collections.Generic namespace, which contains several classes defining generic collections. They're called generic because at declaration you specify a type placeholder for the contained objects instead of a specific type. You give the stored objects a specific type only when you create an instance of the collection.

Generics are a huge time saver. If you've ever created custom collections, you know how much code can be involved. Generics in Visual Basic let you create the equivalent of a custom collection in one line of code. You no longer need to create separate custom collections for each type of object you want to store. You simply provide the desired type as you instantiate the generic collection.

The easiest way to see how generics work is with an example. Assume you have a simple Customer class with two public properties (shown as public variables for brevity):
Public Class Customer
    Public Name As String
    Public CreditLimit As Decimal
    Public Sub New(ByVal CustomerName As String, ByVal CustCreditLimit As Decimal)
        Name = CustomerName
        CreditLimit = CustCreditLimit
    End Sub
End Class

You can declare a list of Customers using the generic collection List class like so:
Dim Customers As New System.Collections.Generic.List(Of Customer)

With this single line of code, you've declared a strongly typed list that stores only Customer types and gives you full IntelliSense on the contained Customer objects. You could just as easily create a list of Product or Order objects, effectively creating a set of custom collections without writing all the custom collection code for each type. You can now write code like this:
Dim custA As New Customer("CustA", 1000)
Customers.Add(custA)
Dim custB As New Customer("CustB", 2000)
Customers.Add(custB)
For Each c As Customer In Customers
    MessageBox.Show("Customer: " & c.Name & ", limit: " & c.CreditLimit)
Next
'compile error: Product cannot be converted to Customer
Dim prodA As New Product("ProdA", CDec(29.95))
Customers.Add(prodA)

You also get a performance advantage using generic collections because the stored objects are strongly typed and not kept internally as type Object.

There are other collection generics available in the System.Collections.Generic namespace. For example, the Dictionary(of K,V) collection allows you to specify types for the keys and values. The LinkedList(of T) and Stack(of T) generic collections behave like regular linked lists and stacks, except you're allowed to specify what kinds of objects they'll contain.

You can create your own generic types using the new generic type declaration syntax. Consider a Comparer class that lets you compare different kinds of objects:
Public Class Comparer(Of itemType)
    '...
End Class

You can define multiple type placeholders in a comma-separated list. You can also define constraints restricting which classes can be provided to the generic when it's instantiated:
Public Class Comparer(Of itemType As IComparable)
    '...
End Class

This constraint ensures that Comparer(of T) instances can only be created with classes implementing the IComparable interface. Multiple constraints can also be applied to the class declaration.

As an example, consider an expanded Customer class that implements IComparable:
Public Class Customer
    Implements IComparable

    Public Name As String
    Public CreditLimit As Decimal
   
    Public Sub New(ByVal CustomerName As String, ByVal CustCreditLimit As Decimal)
        Name = CustomerName
        CreditLimit = CustCreditLimit
    End Sub

    Public Function CompareTo(ByVal obj As Object) As Integer _
        Implements
IComparable.CompareTo
        Dim c As Customer = CType(obj, Customer)
        If CreditLimit > c.CreditLimit Then Return 1
        If CreditLimit < c.CreditLimit Then Return -1
        Return 0
    End Function

End Class

A similar Product class is implemented, except that the CompareTo function compares the product prices instead of the customer's credit limits:
Public Class Product
    Implements IComparable
    Public Name As String
    Public Price As Decimal
    Public Sub New(...)...
    Public Function CompareTo(...)...
End Class

Now the Comparer class provides the generic comparison operation:
Public Class Comparer(Of itemType As IComparable)
    Public Function GetLargest(ByVal Item1 As itemType, _
                                              ByVal Item2 As itemType) As itemType
        Dim i As Integer = Item1.CompareTo(Item2)
        If i > 0 Then Return Item1
        If i < 0 Then Return Item2
        Return Nothing
    End Function
End Class

You can now instantiate Comparers with objects of different types:
Dim pc As New Comparer(Of Product)
Dim prod1 As New Product("LittleOne", 10)
Dim prod2 As New Product("BigOne", 100)
Dim lp As Product = pc.GetLargest(prod1, prod2)
MessageBox.Show("The more expensive product is: " & lp.Name)
Dim cc As New Comparer(Of Customer)
Dim cust1 As New Customer("SmallCo", 1000)
Dim cust2 As New Customer("LargeCo", 5000)
Dim lc As Customer = cc.GetLargest(cust1, cust2)
MessageBox.Show("The customer with a higher limit is: " & lc.Name)

Without generics, you'd have to define a comparison class for each type of object you want to compare (for example, ProductComparer and OrderComparer).

Generics can significantly reduce your coding efforts in many common scenarios. Consider using generics when you have multiple classes that vary only by the type of object on which they operate.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章