Wednesday, 22 February 2006

My first generic method

Since starting to use .NET 2.0, I've made quite a lot of use of the Generic Collection classes.

Today however was the first time I've created my own generic method that adapts to the required type for each instance.

The use of the method is to replace the following kind of code:

        Dim rowTest As dsTests.TESTSRow
 
        rowTest = dtTests(0)
 
        If rowTest.TEST_PUBLISHED <> test.Published Then
            OnDataItemChanged(dtTests.TEST_PUBLISHEDColumn.ColumnName, rowTest.TEST_PUBLISHED, test.Published)
            rowTest.TEST_PUBLISHED = test.Published
        End If

Basically, I'm checking if the value has changed, and if it has then I update the DataRow property, and eventually I call a DataAdapter to send the updates back to the database. By doing the compare, I'm only sending real changes back to the database.

My first step was to create a helper method that took an object as a parameter like this:

    Public Shared Sub UpdateDataRowItem1(ByVal row As Data.DataRow, ByVal column As Data.DataColumn, ByVal newValue As Object)
        Dim oldValue As Object = row(column.ColumnName)
        If oldValue <> newValue Then
 
            row(column.ColumnName) = newValue
 
            OnDataItemChanged(column.ColumnName, oldValue, newValue)
        End If
    End Sub

But as the squiggly lines appeared in Visual Studio, I realised that this wasn't going to work if I stuck with the general Object data type - you can't use <> with Object types! The alternatives were to create separate versions of the method for the different types, or I realised I could make use of generics to do the same thing but in a much easier to maintain way.

My first question was "Can you actually have generic methods?", as I didn't really want a whole class to do this. Thanksfully, the answer is Yes. So I updated the method to look like this:

    Public Shared Sub UpdateDataRowItem2(Of t)(ByVal row As Data.DataRow, ByVal column As Data.DataColumn, ByVal newValue As t)
        Dim oldValue As t = CType(row(column.ColumnName), t)
        If oldValue <> newValue Then
 
            row(column.ColumnName) = newValue
 
            OnDataItemChanged(column.ColumnName, oldValue, newValue)
 
        End If
    End Sub

Getting closer, but it was still complaining - "Operator '<>' is not defined for types 't' and 't'". Going back to check the documention, I noticed one of the examples used a 'constraining type' on the type parameter. That is just what I needed too, so the final version is as follows:

    Public Shared Sub UpdateDataRowItem(Of t As IComparable)(ByVal row As Data.DataRow, ByVal column As Data.DataColumn, ByVal newValue As t)
        Dim oldValue As t = CType(row(column.ColumnName), t)
        If oldValue.CompareTo(newValue) <> 0 Then
 
            row(column.ColumnName) = newValue
 
            OnDataItemChanged(column.ColumnName, oldValue, newValue)
 
        End If
    End Sub

No comments: