Using Generics


There are many examples of generic templates in the .NET 2.0 Base Class Library (BCL). Many of them can be found in the System.Collections.Generic namespace, but others are scattered through the BCL as appropriate. Many of the examples focus on generic collection types, but this is only because it is here that the performance gains due to generics are most notable. In other cases, generics are used less for performance gains than for the strong typing benefits they provide. As noted earlier, anytime you use a collection datatype, you should consider using the generic equivalent instead.

A generic is often written as something like List(Of T). The type (or class) name in this case is List. The letter T is a placeholder, much like a parameter. It indicates where you must provide a specific type value to customize the generic. For instance, you might declare a variable using the List(Of T) generic:

 Dim data As New List(Of Date)

In this case, you’re specifying that the type parameter, T, is a Date. By providing this type, you are specifying that the list will only contain values of type Date. To make this clearer, let’s contrast the new List(Of T) collection with the older ArrayList type.

When you work with an ArrayList, you are working with a type of collection that can store many types of values at the same time:

 Dim data As New ArrayList() data.Add("Hello") data.Add(5) data.Add(New Customer())

This ArrayList is loosely typed, internally always storing the values as type Object. This is very flexible, but relatively slow because it is late bound. Of course, it offers the advantage of being able to store any datatype, with the disadvantage that you have no control over what’s actually stored in the collection.

The List(Of T) generic collection is quite different. It isn’t a type at all; it is just a template. A type isn’t created until you declare a variable using the template:

 Dim data As New Generic.List(Of Integer) data.Add(5) data.Add(New Customer()) ' throws an exception data.Add("Hello") ' throws an exception

When you declare a variable using the generic, you must provide the type of value that the new collection will hold. The result is that a new type is created - in this case, a collection that can only hold Integer values.

The important thing here is that this new collection type is strongly typed for Integer values. Not only does its external interface (its Item and Add methods, for instance) require Integer values, but its internal storage mechanism only works with type Integer. This means that it is not late bound like ArrayList, but rather is early bound. The net result is much higher performance, along with all the type-safety benefits of being strongly typed.

Generics are useful because they typically offer a higher performance option compared to traditional classes. In some cases, they can also save you from writing code, as generic templates can provide code reuse where traditional classes cannot. Finally, generics can sometimes provide better type safety compared to traditional classes, as a generic adapts to the specific type you require, while classes often must resort to working with a more general type such as Object.

Note that generics come in two forms: generic types and generic methods. For instance, List(Of T) is a generic type in that it is a template that defines a complete type or class. In contrast, some otherwise normal classes have single methods that are just method templates and that assume a specific type when they are called. We’ll look at both scenarios.

Generic Types

Now that you have a basic understanding of generics and how they compare to regular types, let’s get into some more detail. To do this, you’ll make use of some other generic types provided in the .NET Framework. A generic type is a template that defines a complete class, structure, or interface. When you want to use such a generic, you declare a variable using the generic type, providing the real type (or types) to be used in creating the actual type of your variable.

Basic Usage

To begin, create a new Windows Application project named Generics. On Form1 add a Button (named btnDictionary) and a TextBox control (named txtDisplay). Set the TextBox control’s Multiline property to True and anchor it to take up most of the form. The result should look something like what is shown in Figure 7-1.

image from book
Figure 7-1

First, consider the Dictionary(Of K, T) generic. This is much like the List(Of T) discussed earlier, but this generic requires that you define the types of both the key data and the values to be stored. When you declare a variable as Dictionary(Of K, T), the new Dictionary type that is created only accepts keys of the one type and values of the other.

Add the following code in the click event handler for btnDictionary:

  txtDisplay.Clear() Dim data As New Generic.Dictionary(Of Integer, String) data.Add(5, "Rocky") data.Add(15, "Mary") For Each item As KeyValuePair(Of Integer, String) In data   txtDisplay.AppendText("Data: " & item.Key & ", " & item.Value)   txtDisplay.AppendText(Environment.NewLine) Next txtDisplay.AppendText(Environment.NewLine) 

As you type, watch the IntelliSense information on the Add method. Notice how the key and value parameters are strongly typed based on the specific types provided in the declaration of the data variable. In the same code, you can create another type of Dictionary:

 txtDisplay.Clear() Dim data As New Generic.Dictionary(Of Integer, String) Dim info As New Generic.Dictionary(Of Guid, Date) data.Add(5, "Rocky") data.Add(15, "Mary") For Each item As KeyValuePair(Of Integer, String) In data   txtDisplay.AppendText("Data: " & item.Key & ", " & item.Value)   txtDisplay.AppendText(Environment.NewLine) Next info.Add(Guid.NewGuid, Now) For Each item As KeyValuePair(Of Guid, Date) In info   txtDisplay.AppendText("Info: " & item.Key.ToString & ", " & item.Value)   txtDisplay.AppendText(Environment.NewLine) Next txtDisplay.AppendText(Environment.NewLine) 

This code contains two completely different types. Both have the behaviors of a Dictionary, but they are not interchangeable because they have been created as different types.

Generic types may also be used as parameters and return types. For instance, add the following method to Form1:

  Private Function LoadData() As Generic.Dictionary(Of Integer, String)   Dim data As New Generic.Dictionary(Of Integer, String)   data.Add(5, "Rocky")   data.Add(15, "Mary")   Return data End Function 

To call this method from the btnDictionary_Click method, add this code:

  Dim results As Generic.Dictionary(Of Integer, String) results = LoadData() For Each item As KeyValuePair(Of Integer, String) In results   txtDisplay.AppendText("Results: " & item.Key & ", " & item.Value)   txtDisplay.AppendText(Environment.NewLine) Next txtDisplay.AppendText(Environment.NewLine) 

The results of running this code are shown in Figure 7-2.

image from book
Figure 7-2

The reason why this works is because both the return type of the function and the type of the data variable are exactly the same. Not only are they both Generic.Dictionary derivatives, they have exactly the same types in the declaration.

The same is true for parameters:

 Private Sub DoWork(ByVal values As Generic.Dictionary(Of Integer, String))   ' do work here End Sub

Again, the parameter type is not only defined by the generic type but also by the specific type values used to initialize the generic template.

Inheritance

It is possible to inherit from a generic type as you define a new class. For instance, the .NET BCL defines the System.ComponentModel.BindingList(Of T) generic type. This type is used to create collections that can support data binding. You can use this as a base class to create your own strongly typed, data-bindable collection. Add new classes named Customer and CustomerList to the project with the following code:

  Public Class Customer   Private mName As String   Public Property Name() As String     Get       Return mName     End Get     Set(ByVal value As String)       mName = value     End Set   End Property End Class Public Class CustomerList   Inherits System.ComponentModel.BindingList(Of Customer)   Private Sub CustomerList_AddingNew(ByVal sender As Object, _     ByVal e As System.ComponentModel.AddingNewEventArgs) Handles Me.AddingNew     Dim cust As New Customer     cust.Name = "<new>"     e.NewObject = cust   End Sub End Class 

When you inherit from BindingList(Of T), you must provide a specific type - in this case, Customer. This means that your new CustomerList class extends and can customize BindingList(Of Customer). Here you’re providing a default value for the Name property of any new Customer object added to the collection.

When you inherit from a generic type, you can employ all the normal concepts of inheritance, including overloading and overriding methods, extending the class by adding new methods, handling events, and so forth.

To see this in action, add a new Button named btnCustomer to Form1 and add a new form named CustomerForm to the project. Add a DataGridView control to CustomerForm and dock it Fill.

Behind btnCustomer, add the following code:

  CustomerForm.ShowDialog() 

Then add the following code behind CustomerForm:

  Dim list As New CustomerList Private Sub CustomerForm_Load(ByVal sender As System.Object, _   ByVal e As System.EventArgs) Handles MyBase.Load   DataGridView1.DataSource = list End Sub 

This code creates an instance of CustomerList and makes it the DataSource for the grid control. When you run the program and click the button to open the CustomerForm, notice that the grid contains a newly added Customer object. As you interact with the grid, new Customer objects are automatically added, with a default name of <new>. An example is shown in Figure 7-3.

image from book
Figure 7-3

All this functionality of adding new objects and setting the default Name value occurs because CustomerList inherits from BindingList(Of Customer).




Professional VB 2005 with. NET 3. 0
Professional VB 2005 with .NET 3.0 (Programmer to Programmer)
ISBN: 0470124709
EAN: 2147483647
Year: 2004
Pages: 267

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net