Link to home
Start Free TrialLog in
Avatar of rutledgj
rutledgj

asked on

Passing generic lists by val

Is there a way to pass a generic list (List of T) by val instead of By Ref?

I created a test app that had this:

Public Class Vendor
   private m_Id as integer
   public property ID as integer
      Get
            Return (m_id)
        End Get
        Set(ByVal value As integer)
            m_id= value
        End Set
    End Property
end Class



No I created another class

Public class Test
  private mList as new list(of Vendor)

  public sub New(VendorList as list(of Vendor))
      mList = VendorList
      mList.Clear()
  end sub
end class


No in main form I click a button and do this:

Dim myList As New List(Of Vendor)
        For i As Integer = 0 To 10
            Dim v As New Vendor
            v.Id= i
            myList.Add(v)
        Next

        Dim t As New Test(myList)
        MsgBox("List Count: " & CStr(myList.Count))



The results show that the clear function in the Test class cleared the passed in list even though it was passed by val.   Back in form1 the msgbox shows the count as 0.

Is there a way I can pass the list to Test without it actually clearing the original list?

Avatar of wdosanjos
wdosanjos
Flag of United States of America image

I think you just need to remove the .Clear from the Test class as follows:

Public class Test
  private mList as new list(of Vendor)

  public sub New(VendorList as list(of Vendor))
      mList = VendorList
  end sub
end class

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of wdosanjos
wdosanjos
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
Avatar of rutledgj
rutledgj

ASKER

I know that will fix it. The whole point of this was to test if clearing it in the class would affect the original list.  I need a way to pass the original list in so that whatever I do to the list in the Test class does not affect the original list in form1.
Lists are always passed by Ref. You need to explicitly create a copy as follows:

Public class Test
  private mList as new list(of Vendor)

  public sub New(VendorList as list(of Vendor))
      mList = new List(of Vendor)(VendorList)
      mList.Clear()
  end sub
end class

Open in new window

Avatar of Mike Tomlinson
" I need a way to pass the original list in so that whatever I do to the list in the Test class does not affect the original list in form1"

wdosanjos already gave you the correct answer:

    "you need to create a copy explicitly"

What you do intend to do with List in your Test Class?...
I have a related question that I'm having some trouble with.  I have a custom object (created as a structure).  For example purposes, I'll call my object ItemDetails here.  In the course of my application, I do a check to see if the object I'm trying to update already exists in my database.

            Dim UpdatedItem As ItemDetails
            Dim ExistingItems As New List(Of ItemDetails)

            For Each DatabaseRow As DataRow In DatabaseTable.Rows
                UpdatedItem = New ItemDetails

                UpdatedItem = GetItemFromDatabase(DatabaseRow)

                ExistingItems = GetExistingItemDetail(UpdatedItem)

                If Not IsNothing(ExistingItems) Then
                    For I As Integer = 0 To ExistingItems.Count
                        UpdateItemData(UpdatedItem, ExistingItems(I))
                    Next
                Else
                    InsertNewRecord(UpdatedItem)
                End If

                UpdatedItem = Nothing

                Application.DoEvents()
            Next DatabaseRow

Open in new window


To check this, I call a function that is supposed to return a list of my ItemDetails object (GetExistingItemDetail).  When I don't find a matching record, the function is written to return a value of Nothing.  These calls to the function work exactly as expected.

However, when I actually find a duplicate record in the database, the function won't return a valid List(Of ItemDetails).

    Private Function GetExistingItemDetail(ByVal UpdatedItem As ItemDetails) As List(Of ItemDetails)
        Dim FoundItems As New List(Of ItemDetails)
        Dim DatabaseItems As New DataTable
        Dim ExistingAdapter As New OleDb.OleDbDataAdapter

        SQLStr = "SELECT * FROM Items " _
                & "WHERE ItemID = '" & UpdatedItem.ID & "'"

        Try
            ExistingAdapter = New OleDb.OleDbDataAdapter(SQLStr, GAPConn)

            DBConn.Open()
            ExistingAdapter.Fill(DatabaseItems)
        Catch DBException As Exception
            MsgBox("There was a problem retrieving the data for item " & UpdatedItem.ID & vbCrLf _
                   & DBException.Message, MsgBoxStyle.Critical + MsgBoxStyle.OkOnly, "DATABASE ERROR")

            FoundItems = Nothing
        Finally
            ExistingAdapter = Nothing
            DBConn.Close()
        End Try

        ' *********************************************************************
        ' ** If a database error occurred above, return nothing and exit the **
        ' ** function to prevent further execution in this function.         **
        ' *********************************************************************
        If IsNothing(DatabaseItems) Then
            FoundItems = Nothing

            Return FoundItems
            Exit Function
        End If

        ' *********************************************************************
        ' ** If no loans were found, return nothing and exit the function.   **
        ' *********************************************************************
        If DatabaseItems.Rows.Count = 0 Then
            FoundItems = Nothing
            DatabaseItems = Nothing

            Return FoundItems
            Exit Function
        End If

        Try
            For I As Long = 0 To DatabaseItems.Rows.Count - 1
                Dim Item As New ItemDetails
                Dim CurrentItem As DataRow

                CurrentItem = DatabaseItems.Rows(I)

                ' *********************************************************************
                ' **Here's where the Item object is populated.
                ' *********************************************************************

                I = I + 1

                ' *********************************************************************
                ' ** Add the waiver we just populated to the array list, reset the   **
                ' ** temporary waiver object and check for the next record.          **
                ' *********************************************************************
                FoundItems.Add(Item)
                Item = Nothing
                CurrentItem = Nothing
            Next I
        Catch DBException As OleDb.OleDbException
            MsgBox("An error occurred retrieving the data for item " & UpdatedItem.ID)
        End Try

        Return FoundItems
    End Function

Open in new window


If I check the FoundItems object when it actually makes it all the way to the end of the function, I see that it actually contains an item.  But, when I get back to the calling function, the List(Of ItemDetails) that I tried to return appears to be invalid.  Is there something that I'm missing/overlooking here?