Description:
First the explaination of a I have a function that I’ve created. It basically uses reflection to create and return a particular type. Whatever I pass in is what I will get back and the function is complete generic. Heres my two senrios. I also use a class called SafeDataReader, which all it does is simple implement the IDataReader interface and does some behind the scenes things so as to not return a DBNull.Value, if that’s what was returned from the read, but the value you except ie you want a string you get an empty string not a DBNul value. Ok here we go, if I don’t make any sense let me know.

1. I have a class call Abc. It has a property called Name. The constructor is like so… Public Sub New(ByVal dr As SafeDataReader)
2. Now I have a class called AbcXyzManager that inherits from a base class that I’ve created and has a function with the following signature. Protected Function FetchDataObjects(Of T, C As List(Of T))(ByVal objectToCreate As Type, ByVal sqlStatement As String, ByVal params As Core.CSSIDbParameterCollection, Optional ByVal cmdType As CommandType = CommendType.Text) As C
3. Now in a function in the AbcXyzManager class called GetAbcList I setup the sql statement and parameters this function is going to return a List(Of Abc). So the signature of the inherited function would look like so Return FetchDataObjects(Of Abc, List(Of Abc))(GetType(Abc), sql, params).
4. What the code below runs it returns a list of Abc that has 3 items each item has different values.
5. This all works just fine item 1’s Abc.Name = Test1, 2’s Abc.Name = Test2, and 3’s Abc.Name = Test3.
6. Now for the kicker.
7. I do the same exact thing only this time I have a class called Xyz, might have different properties, but the same type of constructor.
8. In the AbcXyzManager I have a function called GetXyzList again I setup everything and then return a List of type Xyz.
9. Again I use the FetchDataObjects the only difference this time is it’s of type Xyz and the list is of type Xyz. So the object that needs to be created is Xyz.
10. When the code runs and reads data creates an instance of Xyz and adds it to the list, everything works fine… Until it reads the next record.
11. When it reads the record, instanciates the Xyz object and calls the constructor everything works as it should. I read the records and setup whatever properties/members need to be in the Xyz object.
12. Now for the real big kicker… Once the newly created object is added to the list. If I look at the list so far only two Xyz objects have been added… you would think that these two items of xyz would have different values for the properties… ie lets say there are two properties Name and Number. Name should be Test1, Number should be 1, because that’s what was read from the first record. Now the second item should have a Name property value of Test2 and a Number property value of 2, because again that’s what was read from the second record. However, if I look at the first item the Name value is Test2 and the Number value is 2. It’s as though it’s over writing the previous item(s).

I’ve stepped through my code and watched each and ever value be set each time a record was read. Each time the values are different and prior to adding the newly created Xyz object to the list the first item has different values. As soon as the new Xyz object is added to the list thouh all previous items in the list take on the values from that Xyz object. Again I use the same code for creating a list of type Abc and it works perfectly fine. Here’s the code of the base class function. The problem occurs when it runs the following code.

vb Code:
  1. Do While dr.Read
  2.     retval.Add(Activator.CreateInstance(objectToCreate, New Object() {dr}))
  3. Loop







vb Code:
  1. Protected Function FetchDataObjects(Of T, C As List(Of T))(ByVal objectToCreate As Type, _
  2.                                             ByVal sqlStatement As String, _
  3.                                             ByVal params As DbParameter(), _
  4.                                             Optional ByVal cmdType As CommandType = CommandType.Text) _
  5.                                             As C
  6.             Dim retval As List(Of T) = Nothing
  7.             Try
  8.                 m_Cnn = DbProviderFactories.GetFactory(m_Provider).CreateConnection
  9.                 m_Cnn.ConnectionString = m_CnnStr
  10.                 m_Cnn.Open()
  11.                 If m_Cnn.State = ConnectionState.Open Then
  12.                     m_Cmd = m_Cnn.CreateCommand
  13.                     m_Cmd.CommandText = sqlStatement
  14.                     m_Cmd.CommandType = cmdType
  15.                     If params IsNot Nothing AndAlso params.Count > 0 Then
  16.                        m_Cmd.Parameters.AddRange(params)
  17.                     End If
  18.                     Try
  19.                         Using dr As New Data.Core.SafeDataReader(m_Cmd.ExecuteReader)
  20.                             Try
  21.                                 retval = New List(Of T)
  22.                                 Do While dr.Read
  23.                                     retval.Add(Activator.CreateInstance(objectToCreate, New Object() {dr}))
  24.                                 Loop
  25.                             Catch dbEx As DbException
  26.                                 Throw dbEx
  27.                             Catch ex As Exception
  28.                                 Throw ex
  29.                             End Try
  30.                         End Using
  31.                     Catch dbEx As DbException
  32.                         Throw dbEx
  33.                     Catch ex As Exception
  34.                         Throw ex
  35.                     End Try
  36.                 End If
  37.             Catch ex As Exception
  38.                 Throw ex
  39.             Finally
  40.                 If m_Adapter IsNot Nothing Then
  41.                     m_Adapter.Dispose()
  42.                     m_Adapter = Nothing
  43.                 End If
  44.                 If m_Cmd IsNot Nothing Then
  45.                     m_Cmd.Dispose()
  46.                     m_Cmd = Nothing
  47.                 End If
  48.                 If m_Cnn IsNot Nothing Then
  49.                     'Place closing in try block as the connection
  50.                     'object may still be disposed.
  51.                     Try
  52.                         m_Cnn.Close()
  53.                         m_Cnn.Dispose()
  54.                     Finally
  55.                         m_Cnn = Nothing
  56.                     End Try
  57.                 End If
  58.             End Try
  59.             Return retval
  60.         End Function