Link to home
Start Free TrialLog in
Avatar of pigouvian
pigouvian

asked on

Using .Net 2.0 Generics to instantiate object from datarecord

I am trying to get my head around .NET generics and need the help of a guru.  Here is my code thus far:

            Protected Function GetListFromSP(Of T As New)(ByVal cmd As MySqlCommand) As List(Of T)

                  Dim conn As New MySqlConnection(Me.ConnectionString)
                  Dim reader As MySqlDataReader
                  Dim list As New List(Of T)

                  cmd.Connection = conn

                  Try
                        conn.Open()
                        reader = Me.ExecuteReader(cmd)
                        If reader.HasRows Then
                              Dim rec As IDataRecord
                              For Each rec In reader
                                    list.Add(New T(rec))  ' PROBLEM HERE
                              Next
                        End If
                  Catch ex As Exception
                        If LogExceptions Then WriteToEventLog("SWReports", "Application", "MySQLAccountProvider: " & ex.Message, Diagnostics.EventLogEntryType.Error)
                  Finally
                        conn.Close()
                        conn.Dispose()
                        cmd.Dispose()
                  End Try

                  Return list
            End Function

It appears that generics do not allow the creation of an object with a parameterized constructor.  My questions:  (1) Is it possible to do this; and (2) if not, all of my objects have parameterless constructors -- how do I set properties of T?

Thanks in advance for any help you can provide.
Avatar of graye
graye
Flag of United States of America image

There are a few strange things here... but let's start at the beginning...

Why are you using generics in this situation?  It appears that the "list" collection will always be of type IDataRecord.  
Avatar of pigouvian
pigouvian

ASKER

Unless I completely have misunderstood what generics are about, the list collection will not always be of the type IDataRecord, but rather a list of type T.  The IDataRecord is what I am trying to pass to the constructor for type T.  
I doubt your problem has anything to do with using Generics...

Consider Generics as a "strongly-typed" collection...   Instead of having just a List class (which defaults to the object type), you can now create a List class of a particular type.  This is particularly important when dealing with value types (integers, for example) since they would have to undergo a boxing/unboxing operation each time they are move to/from the object type.   For reference types (such as your example), it's not so important.

I can't see what your T class is... but I suppose it has New() method that takes a IDataRecord as a parameter?   Post a few relevant lines of the T class for us to see.
Since generics are type-safe collections, you need to provide the type in place of "T"; "T" is a type parameter.

Protected Function GetListFromSP(ByVal cmd As MySqlCommand) As List(Of IDataRecord)
               Dim conn As New MySqlConnection(Me.ConnectionString)
               Dim reader As MySqlDataReader
               Dim list As New List(Of IDataRecord)

               cmd.Connection = conn

               Try
                    conn.Open()
                    reader = Me.ExecuteReader(cmd)
                    If reader.HasRows Then
                         For Each rec As IDataRecord In reader
                              list.Add(rec)
                         Next
                    End If
               Catch ex As Exception
                    If LogExceptions Then WriteToEventLog("SWReports", "Application", "MySQLAccountProvider: " & ex.Message, Diagnostics.EventLogEntryType.Error)
               Finally
                    conn.Close()
                    conn.Dispose()
                    cmd.Dispose()
               End Try

               Return list
          End Function
Thank you graye and Chaosian for your continued help.  Perhaps I am going about my DAL the entirely wrong way.  Any suggestions you have would be greatly appreciated.  As for the current plan, the T class would be one of several different objects (account, transaction, user, invoice, etc.).  Here is an example for the particular object called 'Account':


'*** DAL Base Class

      Public MustOverride Class DALBaseClass

            Protected Function GetListFromSP(Of T As New)(ByVal cmd As MySqlCommand) As List(Of T)
            'See above'
            End Function
      End Class

'*** mySQL Implementation of account provider

      Public Class mySQLAccountProvider
            Inherits AccountProvider
            
            'Non-relevant code omitted

            Public Overrides Function GetAccountsByUser(ByVal x500 As String) As List(Of Ledger.Account)
                  Dim cmd As New MySqlCommand
                  Dim list As New List(Of Ledger.Account)
                  Dim trans As New OracleTransactionProvider

                  cmd.CommandText = "pr_GetAccountsByX500"
                  cmd.CommandType = CommandType.StoredProcedure
                  cmd.Parameters.Add("prm_x500", MySqlDbType.String).Value = x500

                  list = Me.GetListFromSP(Of Ledger.Account)(cmd)
                  trans.SetAccountBalances(list)

                  Return list

            End Function

      End Class


'*** Account object

      Public Class Account
            Inherits Objects.ObjectsBaseClass
            Implements IComparable, IEditableObject

            'Non-relevant code omitted

#Region "Constructors"
            Public Sub New()

            End Sub
            Public Sub New(ByVal Fund As String, _
             ByVal Area As String, _
             ByVal Org As String, _
             ByVal StartDate As DateTime, _
             ByVal EndDate As DateTime, _
             ByVal LongDescription As String, _
             ByVal ShortDescription As String, _
             ByVal AccountTypes As ArrayList)
                  _Fund = Fund
                  _Area = Area
                  _Org = Org
                  _StartDate = StartDate
                  _EndDate = EndDate
                  _LongDescription = LongDescription
                  _ShortDescription = ShortDescription
                  _AccountTypes = AccountTypes
            End Sub
            Public Sub New(ByVal dr As IDataRecord)
                  _Fund = Me.GetRecordValue(Of String)("Fund", dr)
                  _Area = Me.GetRecordValue(Of String)("Area", dr)
                  _Org = Me.GetRecordValue(Of String)("Org", dr)
                  _StartDate = Me.GetRecordValue(Of DateTime)("PeriodStart", dr)
                  _EndDate = Me.GetRecordValue(Of DateTime)("PeriodEnd", dr)
                  _LongDescription = Me.GetRecordValue(Of String)("Title", dr)
                  '_ShortDescription = Me.GetRecordValue(Of String)("ShortDescription", dr)
            End Sub

#End Region
#Region "Methods"

#End Region
#Region "Helper Functions"

#End Region

      End Class
SOLUTION
Avatar of graye
graye
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks for the link, graye.  One of the related articles seems to validate my fear that I cannot use a parameterized constructor for T.  This then raises the question can I even get/set the properties of T, or call one of T's methods?  Or should I just write type-specific routines?  What are your thoughts?
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Excellent!  Thanks, Chaosian.  While I probably have received by 500 pts worth, if I may impose on you and graye I would certainly be appreciative of any advice you may have.  What are your thoughts on best practices when it comes to composing a DAL using objects rather than datasets?
I'd seriously reconsider the original premise that a data access layer should be created with hand-made objects.

Personally, I'd use a disconnected DataTable to store my info...  That's essentially what you're doing.... you're recreating (from scratch) what researchers have already taken years to develop (namely disconnected DataSet).   You can use an XSD file to create a strongly-typed DataSet (using no code at all) that will end up equivalent to what you'd do by hand.
Actaully, graye, there's an objectdatasource in 2.0 now... that's the way I'd go about it.

In fact, by adding the tables from your database to the project, your DAL is created for you using the objectdatatable, objectdataadapter, etc -- each table has it's own objects created for you that you can simply drag-and-drop to your forms.