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
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)
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)
_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
For Each item As T In list
_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
_resultDataSet.Tables.Add(_resultDataTable)
Return _resultDataSet
End Function
Private Delegate Function _
_getPropertyDelegate(Of T)(ByVal _
item As T) As 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
_getPropertyValue = New DynamicMethod("_getPropertyValue", _
GetType(Object), _arg, _
GetType(Integer).Module)
_ilGenerator = _getPropertyValue.GetILGenerator()
_ilGenerator.Emit(OpCodes.Ldarg_0)
_ilGenerator.Emit(OpCodes.Callvirt, _propertyInfo.GetGetMethod())
If Not _propertyInfo.PropertyType.IsClass Then
_ilGenerator.Emit(OpCodes.Box, _
_propertyInfo.GetGetMethod.ReturnType())
_ilGenerator.Emit(OpCodes.Ret)
Return CType(_getPropertyValue.CreateDelegate(_
GetType(_getPropertyDelegate(Of T))), _
_getPropertyDelegate(Of T))
End Function
Native (Uses GetValue)
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()
_itemProperties = list.Item(0).GetType().GetProperties()
For Each p As PropertyInfo In _itemProperties
_resultDataTable.Columns.Add(p.Name, _
p.GetGetMethod.ReturnType())
Next
For Each item As T In list
_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
_resultDataSet.Tables.Add(_resultDataTable)
Return _resultDataSet
End Function
Performance

I used 75,000 records for this test.
Pilot Front End

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!