Click here to Skip to main content
Licence CPOL
First Posted 4 Nov 2006
Views 70,913
Bookmarked 26 times

Generic List(Of) to DataSet: Three Approaches

By | 4 Nov 2006 | Article
Turn a List(Of) into a DataSet in three different ways and check performance.

Introduction

This article is a small pilot I wrote to test three ways to convert a List(Of Any Class) into a DataSet. I also included some performance images to show which methods appears to be better.

Conventional

'
' Conventional
'
Private Function GetDataSetConventional(ByVal list As _
        List(Of FileSearchResultItem)) As DataSet
    Dim _result As New DataSet()
    _result.Tables.Add("results")
    _result.Tables("results").Columns.Add("Index")
    _result.Tables("results").Columns.Add("Image")    
    _result.Tables("results").Columns.Add("Row")
    _result.Tables("results").Columns.Add("Name")
    _result.Tables("results").Columns.Add("Size")
    _result.Tables("results").Columns.Add("IsDirectory")
    _result.Tables("results").Columns.Add("Files")

    For Each item As FileSearchResultItem In list
        Dim newRow As DataRow = _
            _result.Tables("results").NewRow()
        newRow("Row") = item.Index
        newRow("Image") = item.Image
        newRow("Name") = item.Name
        newRow("Size") = item.Size
        newRow("Files") = item.Files
        newRow("IsDirectory") = item.IsDirectory
        _result.Tables("results").Rows.Add(newRow)
    Next
    Return _result
End Function

Hacked (Uses Dynamic Methods)

'
' Hacked
'
Private Function GetDataSetHacked(Of T)(ByVal _
        list As List(Of T)) As DataSet    
    Dim _resultDataSet As New DataSet()    
    Dim _resultDataTable As New DataTable("results")
    Dim _resultDataRow As DataRow = Nothing    
    Dim _itemProperties() As PropertyInfo = _
         list.Item(0).GetType().GetProperties()
    Dim _callPropertyValue(_itemProperties.Length()) _
         As _getPropertyDelegate(Of T)

    '
    ' Meta Data.
    ' Each item property becomes a column in the table 
    ' Build an array of Property Getters, one for each Property 
    ' in the item class. Can pass anything as [item] it is just a 
    ' place holder parameter, later we will invoke it with the
    ' correct item. This code assumes the runtime does not change
    ' the ORDER in which the proprties are returned.
    '
    _itemProperties = list.Item(0).GetType().GetProperties()
    Dim i As Integer = 0
    
    For Each p As PropertyInfo In _itemProperties
        _callPropertyValue(i) = _
          CreateGetPropertyValueDelegate(CType(list.Item(0), _
          T), p.Name)
        _resultDataTable.Columns.Add(p.Name, _
                  p.GetGetMethod.ReturnType())
        i += 1    
    Next    
    '    
    ' Data    
    '
    For Each item As T In list        
        '
        ' Get the data from this item into a DataRow
        ' then add the DataRow to the DataTable.
        ' Eeach items property becomes a colunm.
        '
        _itemProperties = item.GetType().GetProperties()        
        _resultDataRow = _resultDataTable.NewRow()
        i = 0        
        For Each p As PropertyInfo In _itemProperties            
            _resultDataRow(p.Name) = _
               _callPropertyValue(i).Invoke(item)
            i += 1
        Next        
        _resultDataTable.Rows.Add(_resultDataRow)    
    Next    
    '    
    ' Add the DataTable to the DataSet, We are DONE!
    '
    _resultDataSet.Tables.Add(_resultDataTable)
    Return _resultDataSet
End Function

'
' Delegate to call DynamicMethod
'
Private Delegate Function _
       _getPropertyDelegate(Of T)(ByVal _
       item As T) As Object
'
' Builds a Dynamic Method to read the peoperty of an object
'
Private Function CreateGetPropertyValueDelegate(Of T)(ByVal _
        item As T, ByVal itemName As Object) As _
        _getPropertyDelegate(Of T)

    Dim _arg() As Type = {GetType(T)}
    Dim _propertyInfo As PropertyInfo = _
        item.GetType().GetProperty(itemName, _
        BindingFlags.Public Or BindingFlags.Instance)
    Dim _getPropertyValue As DynamicMethod = Nothing
    Dim _ilGenerator As ILGenerator = Nothing

    '
    ' Create the funciton
    '
    _getPropertyValue = New DynamicMethod("_getPropertyValue", _
                        GetType(Object), _arg, _
                        GetType(Integer).Module)
    '
    ' Write the body of the function.
    '
    _ilGenerator = _getPropertyValue.GetILGenerator()
    _ilGenerator.Emit(OpCodes.Ldarg_0)
    _ilGenerator.Emit(OpCodes.Callvirt, _propertyInfo.GetGetMethod())
    ' Box value types.
    If Not _propertyInfo.PropertyType.IsClass Then
        _ilGenerator.Emit(OpCodes.Box, _
                     _propertyInfo.GetGetMethod.ReturnType())
    _ilGenerator.Emit(OpCodes.Ret)
    '
    ' Return the Delegate
    '
    Return CType(_getPropertyValue.CreateDelegate(_
                 GetType(_getPropertyDelegate(Of T))), _
                 _getPropertyDelegate(Of T))
End Function

Native (Uses GetValue)

'
' Native
'
Private Function GetDataSetNative(Of T)(ByVal _
        list As List(Of T)) As DataSet
    Dim _resultDataSet As New DataSet()    
    Dim _resultDataTable As New DataTable("results")
    Dim _resultDataRow As DataRow = Nothing    
    Dim _itemProperties() As PropertyInfo = _
         list.Item(0).GetType().GetProperties()    
    '    
    ' Meta Data. 
    '
    _itemProperties = list.Item(0).GetType().GetProperties()
    For Each p As PropertyInfo In _itemProperties
        _resultDataTable.Columns.Add(p.Name, _
                  p.GetGetMethod.ReturnType())
    Next
    '
    ' Data
    '
    For Each item As T In list
        '
        ' Get the data from this item into a DataRow
        ' then add the DataRow to the DataTable.
        ' Eeach items property becomes a colunm.
        '
        _itemProperties = item.GetType().GetProperties()
        _resultDataRow = _resultDataTable.NewRow()
        For Each p As PropertyInfo In _itemProperties
            _resultDataRow(p.Name) = p.GetValue(item, Nothing)
        Next
        _resultDataTable.Rows.Add(_resultDataRow)
    Next
    '
    ' Add the DataTable to the DataSet, We are DONE!
    '
    _resultDataSet.Tables.Add(_resultDataTable)
    Return _resultDataSet
End Function

Performance

Conventional

I used 75,000 records for this test.

Pilot Front End

FrontEnd

I will not comment on the performance much. I ran 5 series for each method, and it appears all things equal, the Hacked IL method runs faster, as much as twice faster. Incredibly, the Conventional method, which is the stupidest of all, does not do that bad as you can see. The question remains, should we use these kinds of tricks cause or should we attach ourselves to more conventional programming and be more compatible with future versions? I leave the reader to decide.

Hope you enjoy it, and please feedback if possible. Thanks!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

arapallo

Web Developer

United States United States

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionBugs PinmemberRaam0015:05 6 Oct '11  
Questionxml Pinmembermaoie19:06 28 Sep '11  
QuestionVB data structures PinmemberNotAndrewTurvil23:16 16 Aug '11  
GeneralExcellent article PinmemberMember 371968111:29 8 Feb '11  
QuestionExcellent, I was trying to do my testing - can we have the code for yours? PinmemberMember 287586421:00 21 Jun '10  
GeneralError while converting List to DataSet in C#.NET 3.5 Pinmembershaileshbhadane19:03 16 Nov '09  
GeneralGetting an error when i run the code PinmemberMember 13630759:22 18 Sep '08  
QuestionTranslate Method to c# PinmemberEowin061:34 20 Apr '07  
GeneralStrangesness Pinmemberarapallo6:14 6 Nov '06  
GeneralFeedBack Pinmemberarapallo1:53 6 Nov '06  
GeneralMeasurement results PinmemberRobert Rohde1:11 6 Nov '06  
GeneralRe: Measurement results Pinmemberarapallo1:45 6 Nov '06  
:-DYes, the idea is which way of getting converting a Class Instance into a DataSet. I am simply showing how fast each method
fills the DataSet. Yes of course the only difference is in getting the value out of the Instance and into the DataSet and timing it.
 
Also, My goal was to show if it makes sense to use Low level tricks such as Dynamic Methods and IL Operations rather than using
the Language functionality.
 
I di this cause in very version of VB or C#, there are allways programmers who break the rules like the HACKED version, and I think this is not a good idea, MS will probably never change the Convettional way, but the will certanly change the IL instructions, therefore breaking your code.
 
thanks for the feedback.
 
Note:
Since all three mthods add rows to the DataSet this part is Static as far as measuring performance therefore this test,
checks how fast each method adds each row.
 

GeneralRe: Measurement results Pinmemberarapallo1:58 6 Nov '06  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120529.1 | Last Updated 4 Nov 2006
Article Copyright 2006 by arapallo
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid