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
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")
' Do any post processing
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 _
Public Function Compare(ByVal x As T, ByVal y As T) _
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( _
Return System.Collections.Comparer.Default.Compare( _
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
. 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 _
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 sortin 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.