Wont Work...!!!
Wont Work...!!!
Wont Work...!!!
Wont Work...!!!
Wont Work...!!!
Wont Work...!!! Wont Work...!!! Wont Work...!!! Wont Work...!!! Wont Work...!!! Wont Work...!!! Wont Work...!!! Wont Work...!!!
Wont Work...!!! Wont Work...!!!
Wont Work...!!!
Go Back  Xtreme Visual Basic Talk > > > Wont Work...!!!


Reply
 
Thread Tools Display Modes
  #1  
Old 08-22-2009, 09:45 PM
HQcool22's Avatar
HQcool22 HQcool22 is offline
Regular
 
Join Date: Jun 2009
Location: Oregon
Posts: 94
Default Wont Work...!!!


Ok, I got this code that reads a line that looks like this,
Meal:0

Then it splits the line by ":" and i get the result of the the "0". Then my code takes that 0 and turns it into a 1. That works fine... but when i run the code again it does not turn it into a 2... it stays a 1. Ive tryed everything i can think of and i probably did something stupide but heres my code.

Code:
                Dim ex As System.IO.StreamReader
                Dim ev As System.IO.StreamWriter
                Dim ex1 As String
                ex = New System.IO.StreamReader("Meals\" & ComboBox1.SelectedItem.ToString & ".txt")
                ex1 = ex.ReadLine
                ex1.Split(":")
                ev1 = CInt(Val(ex1(1)))
                modNEWMEAL.ev2 = ev1
                modNEWMEAL.ev2 = modNEWMEAL.ev2 + 1
                ex1 = ex.ReadToEnd
                ex.Dispose()
                ex.Close()
                ev = New System.IO.StreamWriter("Meals\" & ComboBox1.SelectedItem.ToString & ".txt")
                ev.WriteLine(ComboBox1.SelectedItem & ":" & modNEWMEAL.ev2 & Environment.NewLine & ex1 & TextBox1.Text)
                ev.Dispose()
                ev.Close()
modNEWMEAL.ev2 is a,
Public ev2 as Integer (This is in a module)

Thanks for any help

Note: I really dont understand why this is not working... vb.net is strange sometimes.
__________________
I know stuff!
Reply With Quote
  #2  
Old 08-23-2009, 10:00 AM
AtmaWeapon's Avatar
AtmaWeaponWont Work...!!! AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

Here's some hypotheses. It turns out the error is really elementary, but poor names for your variables hid it until I started using a debugger to see what's going on. Read along and learn.
  • You're not doing any error checking. For all you know, you're not reading what you think you're reading and CInt(Val(ex1(1))) always returns 0. Have you used a debugger to ensure that ev has 2 elements and ev(1) is not 0?
  • Val() is a naughty function you should never use in my eyes. It's a holdover from VB6 and only works for compatibility reasons. You can't control how it's conversion works, and it will happily convert the string "asdf123a3sdf" into 123, which seems bonkers to me. It's much better to use CInt(), Integer.Parse(), Integer.TryParse(), or System.Convert.ToInt32() to parse integers. They give you more control over the format of the number. When I see Val() in use, I refuse to stop blaming it until it's gone.
  • What the heck is modNEWMEAL? Your casing makes it look like a module that is a constant, which is kind of strange. If it's a module it should be named NewMeal, but we need to have a separate discussion about why you're using a module to store temporary variables. Modules should represent objects that either perform a task or maintain data but should share data amongst all usages; it's a cheap Singleton.
  • Use better variable names. ex, ev, ex1, etc. are variable names that only mean something to you; if someone else is looking at your code they'll get no hints as to what everything is. Name variables using nouns that describe what they are and what they do.
  • ev1 is never declared. This is a compilation error with VB .NET's default settings and causes me to wonder if this is *really* the code that's causing the error. If you don't post the code that causes the error, then I can't help. If this is *exactly* the code that causes the error, do yourself a favor right now. Go to Tools>Options... and expand the "Projects and Solutions" tree node. Select the "VB Defaults" node. Option Strict should be On. Option Explicit should be On. I don't really care what you set Option Compare or Option Infer to, but I leave them at the defaults Binary and On.
  • Since you are not using a Using statement or a Try..Finally block to manage your I/O objects, if anything throws an exception in this method you'll likely leave behind an open handle to the file. This means if this code crashes you'll have to reboot to open the file again. There is almost never a good reason to *not* use a Using statement. There is never a good reason to write I/O code with neither Using statements nor Try..Finally.

It looks like what you want to do (based on the code) is load a file that has a single line of the format "XXXX:0000", where "XXXX" is a don't care and 0000 is some integer with no punctuation. Here's what your code does:
  • Open a file
  • Read the first line of the file.
  • Split the line at any ":" character.
  • Convert the 2nd array element to an integer; if any errors occur use 0.
  • Read the rest of the file and store its contents.
  • Close the file.
  • Open a file for writing.
  • Write a string that consists of a value, ":", the incremented number from earlier, a newline, the rest of the file, and some user-defined text.
  • Close the file.

Here's your broken line:
ex1.Split(":"c)
Like all string functions, this method creates a new object based off of modifying the original string and returns the new object. In this case, it splits the string into tokens and returns an array. However, you don't do anything with the return value! So let's track what happens line by line:
Code:
ex1 = ex.ReadLine ' Assume the file starts with "Meal:0"
'   Now ex1 holds the value "Meal:0".

ex1.Split(":"c) ' See note 1 for why this is different than the original line.
'   Generates the object { "Meal" "0" } from "Meal:0".  The object is not stored.

Dim ev1 As Integer = CInt(Val(ex1(1)))
'   This is where things get complicated. Let's resolve each function call.
'       CInt(Val(ex1(1))): ex1 is a string, so indexing into it retrieves a character.
'       CInt(Val("e"c)): Val() can't convert "e" to a number, so 0 is returned.
'       CInt(0): returns 0
Due to unclear variable names, you accidentally created a scenario where you index a String when you intended to index a String array. You use Val() for the conversion to Integer; Val() silently fails and doesn't alert you to the error. This returns a character that always resolves to 0, therefore you never use the number that's in the file. A secondary problem is you never store the array that you intend to index, so it's impossible to use it.

To fix this problem, I recommend first using appropriate variable names. Always use a noun that describe's a variable's contents for a variable name. Also, you should be storing the result of the split so you can use it later. Ideally, you should replace the multiple places you refer to the file path or control values with variables that describe their contents. Finally, you should be using Using statements to limit the scope of your IO objects and avoid the need to manually dispose of them. If you combine these suggestions, you get something more likely to work and much easier to understand:
Code:
    Private Sub Test()
        ' Get the selected item type
        Dim itemType As String = ComboBox1.SelectedItem.ToString()
        Dim filePath As String = String.Format("Meals\{0}.txt", itemType)

        ' Retrieve the first line and the rest of the file
        Dim firstLine As String
        Dim fileRemainder As String
        Using reader As New StreamReader(filePath)
            firstLine = reader.ReadLine()
            fileRemainder = reader.ReadToEnd()
        End Using

        ' Get the meal count from the line and increment it
        Dim tokens() As String = firstLine.Split(":"c)
        If tokens.Length <> 2 Then
            ' If there are't 2 tokens, the file isn't as you expected so don't continue.
            Throw New InvalidOperationException("The meal file is invalid.")
        End If

        ' Get the current count and increment it
        Dim count As Integer
        If Not Integer.TryParse(tokens(1), count) Then
            ' If the meal count is not a number, the file isn't valid so don't continue.
            Throw New InvalidOperationException("The meal count in the file is invalid.")
        End If
        Dim newCount As Integer = count + 1

        ' Write the new version of the file.
        Using writer As New StreamWriter(filePath)
            writer.WriteLine(String.Format("{0}:{1}", itemType, newCount))
            writer.WriteLine(String.Format("{0}{1}", fileRemainder, TextBox1.Text))
        End Using
    End Sub
I have tested this and it works, but it's also easier to inspect and verify without running.

*Aside*
There's no need to call Close() then Dispose(). Close() is provided because it makes more sense for files, and it calls Dispose(). Call one or the other, but not both, to reduce noise in your code. Alternatively, use a Using statement so you don't have to worry about it.
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #3  
Old 08-24-2009, 08:52 PM
HQcool22's Avatar
HQcool22 HQcool22 is offline
Regular
 
Join Date: Jun 2009
Location: Oregon
Posts: 94
Default

Hello,
Thanks, i got it working right. I named the streamwriter and streamreader something simple and small. Im not very good at naming variables. But the reason there were variables you did not know about or were in different locations is because i was trying to get it to work, by trying to move data around. I failed everytime. I have been using try, catch, finally statments but i only posted the code in the statment not the statment itself. I did not realize val() was so bad. Only reason i put it there was because it threw an error if i did not, saying something about converting array to integer.

Thanks for help
__________________
I know stuff!
Reply With Quote
  #4  
Old 08-25-2009, 06:37 AM
emartinho emartinho is offline
Centurion
 
Join Date: Jan 2009
Location: Toronto, Ontario
Posts: 194
Default

Quote:
Originally Posted by AtmaWeapon View Post
  • Val() is a naughty function you should never use in my eyes. It's a holdover from VB6 and only works for compatibility reasons. You can't control how it's conversion works, and it will happily convert the string "asdf123a3sdf" into 123, which seems bonkers to me. It's much better to use CInt(), Integer.Parse(), Integer.TryParse(), or System.Convert.ToInt32() to parse integers. They give you more control over the format of the number. When I see Val() in use, I refuse to stop blaming it until it's gone.
Hi Atma,

While I agree that Val should not be used, I never saw the highlighted situation above. I've tested this in both VB6 and VB.NET and I get what I expect: Val("asdf123a3sdf") = 0.0
Looking further, I think this was the problem with Val() you wanted to expose. If you're string begins with a number, then Val() returns that number:
Code:
Val("123.4s4abcdf33") = 123.4
The other conversion functions will obviously give an exception.

One other issue is with Regional Settings. Some countries use the comma as the decimal "point". Sometimes companies in these countries configure their databases with American settings but their workstations with local settings (i.e. DB uses period, but workstation uses comma) . Don't ask why, it just happens, I've been stuck in the middle of this type of thing already.
If the program is to handle this type of situation, then there is another difference between Val and other decimal conversion functions to be aware of. If the workstation's decimal point is a comma, but the data has a period (also happens vice-versa), then for "123.4", Val() returns "123" while CDbl() returns 1234!
Not sure which is more "correct", but it is something to watch out for.

Cheers.
-EM
Reply With Quote
  #5  
Old 08-25-2009, 08:30 AM
AtmaWeapon's Avatar
AtmaWeaponWont Work...!!! AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

Ahh, you're correct. I thought I'd memorized what Val() did but was incorrect. There's one more good reason to *never* use Val(): people who never programmed in VB6 have no idea what it does and have to run to documentation.

Regional settings are also another good reason; [c]Val() is completely region-ignorant.
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
Wont Work...!!!
Wont Work...!!!
Wont Work...!!! Wont Work...!!!
Wont Work...!!!
Wont Work...!!!
Wont Work...!!! Wont Work...!!! Wont Work...!!! Wont Work...!!! Wont Work...!!! Wont Work...!!! Wont Work...!!!
Wont Work...!!!
Wont Work...!!!
 
Wont Work...!!!
Wont Work...!!!
 
-->