RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Everyday Use of Generics : Page 4

Generics aren't a Ferrari that you only take out for special occasions; they're more like your trusty pickup, perfectly suited for everyday use.

Reusing Generics Code
At this point, think about the things that your application normally needs to do during the save process that are the same for both tasks and persons. For example, before executing the save you probably want to perform all required validation, display a "saving" message, or other pre-processing. Then the code needs to call the business object to perform the unique processing, such as calling the appropriate Save procedure. Finally, you may have some post-processing in the form, such as displaying a "save complete" message or disabling the Save button until something else is changed.

You may be writing this code now in every form. By writing a generic method, you can write such code one time and use it with every form and with any business object.

To easily use the code in every form, create a base form class. If you haven't spent a lot of time with form classes, see my article, "Give Your Forms a Base" in the March/April 2004 issue of CoDe Magazine.

Ensure every form then inherits from this base form class instead of System.Forms.Form by changing the code in the .Designer.vb file as follows:

   Partial Class GenericMethodExample 
   Inherits BaseWin
Then add the generic save method to the base form class:

   Protected Sub Save(Of T)(ByVal objectToSave As T)
   ' Do any pre-processing
   ' Call the appropriate save method on the 
   ' business object
   Dim _methodInfo As Reflection.MethodInfo
      _methodInfo = GetType(T).GetMethod("Save")
      _methodInfo.Invoke(objectToSave, Nothing)
      ' Do any post processing
   End Sub
The first thing that you will notice is that the generic method is declared slightly differently. The (Of T) syntax indicates that the Save method is a generic method. All generic methods require this syntax. You can define any number of type parameters, such as (Of TSource, TDestination). You can then use whatever type parameter variable(s) you use in the method declaration throughout the method to represent that type.

Author's Note: Though most standards suggest using T or T with a suffix, such as TKey or TValue, you can actually use any letters for the type parameter placeholder.

The method parameter in this example (objectToSave) is also declared to be As T, indicating that an object of the desired type must be passed to this method.

The first lines of code in this method would be your code for any processing required before actually saving the data. For example, this code could call validation methods or display a status message.

This method then uses reflection to call the appropriate Save method on the business object, using the GetMethod call to find the method on the defined business object and then invokes that method.

Any post-processing code comes last, such as displaying a "save complete" status message or disabling the Save button until the user makes another change.

Calling the method is easy. In the Click event for the Save button on each form, add code similar to the following:

   For Each individual As Person In PersonList
This example calls the Save method in the base form class for each person in the List.

The code for tasks is similar:

   For Each item As Task In TaskList
By building generic methods, you can write generalized code that is type safe and works with any business object in your application.

Now that you know how to build a generic method, let's look at the comparer, which not only requires a generic method, but a generic class as well. Here's some code for a simple comparer class:

   Public Class PropertyComparer(Of T)
      Implements IComparer(Of T)
      Private ReadOnly _propertyInfo As Reflection.PropertyInfo
      Private ReadOnly _sortDirection As SortOrder
      Public Sub New(ByVal propertyToSort As String, _
         ByVal sortDirection As SortOrder)
         _sortDirection = sortDirection
         _propertyInfo = GetType(T).GetProperty(propertyToSort, _
            Reflection.BindingFlags.Instance Or _
            Reflection.BindingFlags.Public Or _
            Reflection.BindingFlags.FlattenHierarchy Or _
      End Sub
      Public Function Compare(ByVal x As T, ByVal y As T) _
         As Integer
         Implements IComparer(Of T).Compare
         Dim xValue As Object = _propertyInfo.GetValue(x, Nothing)
         Dim yValue As Object = _propertyInfo.GetValue(y, Nothing)
         If _sortDirection = SortOrder.Ascending Then
            Return System.Collections.Comparer.Default.Compare( _
            xValue, yValue)
            Return System.Collections.Comparer.Default.Compare( _
               yValue, xValue)
         End If
      End Function
   End Class
This code defines a generic PropertyComparer class. It uses the (Of T) syntax to denote that it is a generic class, and implements the IComparer generic interface to support comparing two values.

The class has two fields: _propertyInfo and _sortDirection. The _propertyInfo field retains information on the property of the object selected for the sort. This allows you to sort on any business object property. The _sortDirection field determines whether the sort should be ascending or descending.

The constructor takes the property name as a string and the sort direction and uses reflection to get information on the property based on the property name.

The generic Compare method is called automatically during a sort operation to compare the values and sort them appropriately. This Compare method calls the default comparer for the defined property type. For example, it will call the String comparer for properties of type String.

After the PropertyComparer code is in place, performing the sort using the PropertyComparer class is easy. To sort the TaskList, for example, you use this code:

   TaskList.Sort(New PropertyComparer(Of _
      Task)("TaskName", SortOrder.Ascending))
The built-in Sort method of the generic List class takes a comparer as a parameter. In this example, the Sort method creates a new PropertyComparer for the Task business object. It then passes in the property name designating the Task business object property to use for the sort—in this case the TaskName property. It also defines the sort order. The TaskList is then sorted as defined.

Create your own PropertyComparer class whenever you want to sort on a particular business property or when the default sorting features don't provide all of the power that you need. By creating this class in your base form class or code library, you can easily reuse it for any business object.

Refactor your methods to generic methods when you find similar methods that differ only in the data type that they use. You will greatly minimize the amount of code that you need to write for common functionality.

Deborah Kurata is cofounder of InStep Technologies Inc., a professional consulting firm that focuses on turning your business vision into reality using Microsoft .NET technologies. She has over 15 years of experience in architecting, designing, and developing successful .NET applications. Deborah is the author of several books, including "Doing Objects in Visual Basic 6.0" (SAMS) and "Doing Web Development: Client-Side Techniques" (APress). She is on the INETA Speaker's Bureau and is a well-known speaker at technical conferences.
Email AuthorEmail Author
Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date