Results 1 to 17 of 17

Thread: [RESOLVED] List of

  1. #1

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2010
    Posts
    402

    Resolved [RESOLVED] List of

    Currently I have a programme that reads a text file, and adds each line into a list(of String). This works ok. However the second part to the programme, splits each line of the text file into 3 parts. This is done by using a Class. The class is then added into a different list of, but this time its a list(of lineSplit). Where line split is a user defined class. Now whilst this list contains the correct number of records, with each record being split into 3 (as defined by the class), each record is identical.

    Single stepping the programme shows when the last item is added to the list, it also over writes all the previous items in the list with the new value.

    The code is as follows :-

    Code:
     Dim aDataSplit1 As New aDataSplit
     Dim aRawData As New List(Of String)
     Dim aData As New List(Of aDataSplit)
    
    If OpenFileDialog1.FileName.EndsWith("txt")  Then
                nFileNum = FreeFile()  
                FileOpen(nFileNum, OpenFileDialog1.FileName, OpenMode.Input, OpenAccess.Read, OpenShare.Shared) 
    
                Do While Not EOF(nFileNum)
                    recordToProcess = LineInput(nFileNum)
                    aRawData.Add(recordToProcess)             
                Loop
    End If
    Now the above code works ok, however when I now create a new list with the fields split up, this is where the issue occurs

    Code:
    For Each record As String In aData
                recordToProcess = record
    
    aDataSplit1.columna = Mid(recordToProcess, 1, 6)
    aDataSplit1.columnb = Mid(recordToProcess, 8, 6)
    aDataSplit1.columnc = Mid(recordToProcess, 20, 6)
    
    aData.Add(aDataSplit1)
    
    next

    The class aDataSplt

    Code:
    Public Class aDataSplit
        Public Property Columna As String
        Public Property Columnb As String
        Public Property Columnc As String
    
    End Class
    Any ideas would be helpful

  2. #2
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,745

    Re: List of

    You only create one instance of aDataSplit and then keep changing it in the for loop.
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  3. #3

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2010
    Posts
    402

    Re: List of

    I dont understand what you are saying (or how to fix it). There is only one instance of aDataSplit, however before its contents are changed, the contents are added to the aData List. The process then repeats its self with a different value in aDataSplit, which is added to the aData List ?

    Hence i would expect the aData List to contain a lots of different values
    Last edited by Signalman; Nov 28th, 2023 at 04:25 PM.

  4. #4
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,453

    Re: List of

    Code:
    Dim aRawData As New List(Of String)
    Dim aData As New List(Of aDataSplit)
    
    If OpenFileDialog1.FileName.EndsWith("txt") Then
        aRawData = New List(Of String)(IO.File.ReadAllLines(OpenFileDialog1.FileName))
        aData = aRawData.ConvertAll(Function(s) New aDataSplit With {.Columna = Mid(s, 1, 6), .Columnb = Mid(s, 8, 6), .Columnc = Mid(s, 20, 6)}).ToList
    End If

  5. #5
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,453

    Re: List of

    Why all the classic vb code? If you want to write in classic vb, why not just do so? If you want to write in .net, why not take the time to learn it. I left the Mid statements in my example, but only because I couldn’t remember how it works. Ideally, you’d use [String].SubString instead of Mid

  6. #6

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2010
    Posts
    402

    Re: List of

    Many thanks, however i am still trying to understand why my origional code did what it did.

  7. #7
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,453

    Re: List of

    If I tell you, you’ll just keep using the legacy code

    Code:
    For Each record As String In aData
        recordToProcess = record
        aDataSplit1 = new aDataSplit
        aDataSplit1.columna = Mid(recordToProcess, 1, 6)
        aDataSplit1.columnb = Mid(recordToProcess, 8, 6)
        aDataSplit1.columnc = Mid(recordToProcess, 20, 6)
    
        aData.Add(aDataSplit1)
    
    next

  8. #8
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,453

    Re: List of

    Quote Originally Posted by Signalman View Post
    Many thanks, however i am still trying to understand why my origional code did what it did.
    I’ve never seen this before, but it’s because aDataSplit1 is a reference type variable

  9. #9
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    38,905

    Re: List of

    When you create a class, you are creating a reference type variable. All classes are reference types. What that means is that when you declare the variable:

    Dim aDataSplit1 As New aDataSplit

    You are creating a new object of type aDataSplit, but you are NOT putting that object into the variable aDataSplit1. What you are putting in the variable is essentially the address of the object. The object is sitting somewhere out in memory, and you are sticking the address into the variable.

    Now, when you add the variable to the List, you are only adding what the variable contains, which is the address of the actual object. You aren't adding the object to the List, you are adding the reference to the object to the List. That's the only way that it CAN work. What that means, though, is that you are adding the same address over and over and over. There's only the one object, which you keep changing, and every time you change it, you add its address to the List...again. The address isn't changing, only the object is changing.

    By the end of the loop, you have a bunch of copies of the address of the one and only object. You can get to the object by any of the addresses, since they are all just copies of one another, but there's still only the one object.

    What you need to do is create a new object each time through the loop. You have to be doing something like:

    aDataSplit1 = new aDataSplit()

    at the start of each loop iteration. Only New creates a new object.
    My usual boring signature: Nothing

  10. #10

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2010
    Posts
    402

    Re: List of

    If I tell you, you’ll just keep using the legacy code
    It helps my understanding, I can see where I went wrong now and I think I partly understand why its using the old values. I must confess I did not think you could repetatively create a new data type with the same name. But it Works
    aDataSplit1 = new aDataSplit

    I am still getting use to Classes & methods !!!!!

  11. #11
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,453

    Re: List of

    Quote Originally Posted by Signalman View Post
    It helps my understanding, I can see where I went wrong now and I think I partly understand why its using the old values. I must confess I did not think you could repetatively create a new data type with the same name. But it Works
    aDataSplit1 = new aDataSplit

    I am still getting use to Classes & methods !!!!!
    I don’t approve… : (

  12. #12
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    38,905

    Re: List of

    I don't understand. Are you replying to me or to .Paul?

    A variable is just a variable. You can put whatever you want into it. Variables that are value types, such as integers, dates, doubles, etc., nobody is concerned about replacing the value in the variable. Reference types are no different. You can replace them as often as you want. All they hold is the address of some object that is out in memory, but that's just a certain number of bytes, the same as an integer or a double.

    New is just creating a new object of a certain type out in memory. You are then sticking the address into a variable. You can create as many objects as you have memory for them. Each will have it's own address, and you are just putting the address into a variable. It's not really any different from putting a series of integers into an integer variable. The variable can hold whatever you put in there, so long as it is the right type. Integer variables hold integers, aDataSplit variables hold references to aDataSplit objects.
    My usual boring signature: Nothing

  13. #13
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,453

    Re: List of

    Code:
    Dim aRawData As New List(Of String)
    Dim aData As New List(Of aDataSplit)
    
    If OpenFileDialog1.FileName.EndsWith("txt") Then
        ‘ this reads all of the lines in your txt file into the list
        aRawData = New List(Of String)(IO.File.ReadAllLines(OpenFileDialog1.FileName))
        ‘ for every string in the previous list, this creates a new aDataSplit with the specified parts of the string
        ‘ then adds all of those aDataSplit objects to the list
        aData = aRawData.ConvertAll(Function(s) New aDataSplit With {.Columna = Mid(s, 1, 6), .Columnb = Mid(s, 8, 6), .Columnc = Mid(s, 20, 6)}).ToList
    End If

  14. #14
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    38,905

    Re: List of

    One further point is that you were expecting that putting the variable into the list would essentially copy the object to the list. That's what happens if you have a List( of Integer), so why not with a List(of aDataSplit). In fact, it IS doing exactly the same thing, it's just that the variable only holds the reference to the object, not the object itself.

    Lots of people starting out with classes think that it should be as easy to copy an object as it is to copy an integer, so why mess with these references? In fact, copying objects has no generic solution that will work for all objects. Therefore, to copy an object, you always have to define a copy mechanism, which in some languages would be called a copy constructor, while in others, it might be called a Clone method.

    The problem with copying an object is that it isn't always clear how to do so. Suppose the constructor of the object MUST run for the object to be in good shape? The default copy mechanism would have to call the constructor, but that is only possible if the class has a constructor that takes no arguments. If the constructor takes arguments, then copying isn't possible without supplying values for the arguments.

    Even if the object does have a constructor that takes no arguments, there is no way to guarantee that calling it will perform a good copy in all cases. It's fairly trivial to come up with an object that can't be copied simply by calling the constructor (with or without arguments). All that would be required would be an object that has some property or method called AFTER the constructor has already run. Copying that object by just calling the constructor would not create a real copy at all, as the subsequent step of setting those properties or running those methods, would not have happened.

    So, when it comes to reference types (ALL objects), there is no generic way to perform a deep copy such that you end up with a valid copy of any possible object. With no way for that to be possible, no language tries it. Instead, you get a shallow copy, which is just a copy of the address of the object. If you want more than that, you have to write the method to do so yourself. When I want to be able to copy objects, I write a Clone method that returns the copy, which is a new instance of the object that was cloned. These can get quite involved.
    My usual boring signature: Nothing

  15. #15
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    38,905

    Re: List of

    Quote Originally Posted by .paul. View Post
    Code:
    Dim aRawData As New List(Of String)
    Dim aData As New List(Of aDataSplit)
    
    If OpenFileDialog1.FileName.EndsWith("txt") Then
        ‘ this reads all of the lines in your txt file into the list
        aRawData = New List(Of String)(IO.File.ReadAllLines(OpenFileDialog1.FileName))
        ‘ for every string in the previous list, this creates a new aDataSplit with the specified parts of the string
        ‘ then adds all of those aDataSplit objects to the list
        aData = aRawData.ConvertAll(Function(s) New aDataSplit With {.Columna = Mid(s, 1, 6), .Columnb = Mid(s, 8, 6), .Columnc = Mid(s, 20, 6)}).ToList
    End If
    Teaching a person who is learning how to walk a method for sprinting.
    My usual boring signature: Nothing

  16. #16
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,453

    Re: List of

    Quote Originally Posted by Shaggy Hiker View Post
    Teaching a person who is learning how to walk a method for sprinting.
    With the declaring aDataSplit1 as a new object, I mentioned how to do that in code before your more knowledgeable explanation. I really didn’t want to answer. It’s just enabling poor coding…

  17. #17
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,238

    Re: List of

    If you actually want the lines of the file in a List(Of String) then do this:
    Code:
    Dim lines = File.ReadLines(filePath).ToList()
    Don't call ReadAllLines first, which returns an array, and then copy the contents of that into a List. If you don't actually want the lines though, but rather want the results of processing the lines, then you should just process them and put the result of that into a List. You can do that in a loop with File.ReadLines as a the source, so you only read one line at a time and discard it after processing, rather than populating an array that you don't really need, e.g.
    Code:
    Dim data As New List(Of SomeType)
    
    For Each line In File.ReadLines(filePath)
        Dim item As New SomeType
    
        'Transfer data from line to item here.
    
        data.Add(item)
    Next
    Once you understand the principles, you can make it more succinct with a LINQ query, collapsing the body of the loop to a Select call, e.g.
    Code:
    Dim data = File.ReadLines(filePath).Select(Function(line) New SomeType).ToList()
    As it is, that code would just add "empty" SomeType objects to the list but you can add whatever processing you like to that Select call.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width