Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Using .Net 2.0 Generics to instantiate object from datarecord

Posted on 2006-07-23
11
Medium Priority
?
623 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
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
 
LVL 41

Assisted Solution

by:graye
graye earned 1000 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 1000 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

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This tutorial demonstrates one way to create an application that runs without any Forms but still has a GUI presence via an Icon in the System Tray. The magic lies in Inheriting from the ApplicationContext Class and passing that to Application.Ru…
Well, all of us have seen the multiple EXCEL.EXE's in task manager that won't die even if you call the .close, .dispose methods. Try this method to kill any excels in memory. You can copy the kill function to create a check function and replace the …
This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.
Have you created a query with information for a calendar? ... and then, abra-cadabra, the calendar is done?! I am going to show you how to make that happen. Visualize your data!  ... really see it To use the code to create a calendar from a q…
Suggested Courses

721 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