Solved

Using .Net 2.0 Generics to instantiate object from datarecord

Posted on 2006-07-23
11
606 Views
Last Modified: 2011-08-18
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.
0
Comment
Question by:pigouvian
  • 4
  • 4
  • 3
11 Comments
 
LVL 41

Expert Comment

by:graye
ID: 17168009
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.  
0
 

Author Comment

by:pigouvian
ID: 17168152
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.  
0
 
LVL 41

Expert Comment

by:graye
ID: 17169455
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.
0
 
LVL 24

Expert Comment

by:Jeff Certain
ID: 17170015
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
0
 

Author Comment

by:pigouvian
ID: 17170734
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
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 41

Assisted Solution

by:graye
graye earned 250 total points
ID: 17171277
OK... it's becoming clear(er) what you're trying to do...

I see now that you're not trying to *consume* a generic type in your application... instead you're trying to *create* a generic type for your application.   Whew... sorry for the confusion.

OK, here is a pretty good article that talks about how to "decorate" the Class statement so that it becomes a Generic class.  http://msdn2.microsoft.com/en-us/library/4a1b71ta.aspx

I've still got some other concerns:
1) that spooky (Of T As New) in the function declaration
2) whether or not this is a good candidate for generics at all
0
 

Author Comment

by:pigouvian
ID: 17171676
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?
0
 
LVL 24

Accepted Solution

by:
Jeff Certain earned 250 total points
ID: 17171828
Well, you can certainly create your own generic classes.... however, you can't call methods on T that aren't common to all Ts. By default this is all objects, so you're limited to the ToString and GetType methods.

This behavior is by design, and makes total sense. After all, trying to call .Add on an integer wouldn't make any sense.

You need to look into constraints, so that you can access more of your class.  http://www.developer.com/net/vb/article.php/3521486 shows a little bit more of what I mean.

You may need to make your classes implement an interface to get them to work well in your generic type.

And, yes.. of T As New probably has to go. :)
0
 

Author Comment

by:pigouvian
ID: 17172073
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?
0
 
LVL 41

Expert Comment

by:graye
ID: 17172462
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.
0
 
LVL 24

Expert Comment

by:Jeff Certain
ID: 17173024
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.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Introduction When many people think of the WebBrowser (http://msdn.microsoft.com/en-us/library/2te2y1x6%28v=VS.85%29.aspx) control, they immediately think of a control which allows the viewing and navigation of web pages. While this is true, it's a…
Creating an analog clock UserControl seems fairly straight forward.  It is, after all, essentially just a circle with several lines in it!  Two common approaches for rendering an analog clock typically involve either manually calculating points with…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now