I'm looking to find out if there is a standard or preferred way for using the (Me) keyword in VB.Net syntax.
Currently I know of 3 ways to use (Me).
Without the (Me) keyword:
Cursor = Cursors.WaitCursor
RadioButtonSortBySurname.Checked = True
LightGrid.SortColumn(2)
LightGrid.Columns(2).LastSortState = Ascending
LightGrid.SortColumn(1)
LightGrid.Columns(1).LastSortState = Ascending
Cursor = Cursors.Default
LightGrid.StatusRowText = ""
LightGrid.Select()
(Me) in a Using structure:
Using Me
Cursor = Cursors.WaitCursor
RadioButtonSortBySurname.Checked = True
LightGrid.SortColumn(2)
LightGrid.Columns(2).LastSortState = Ascending
LightGrid.SortColumn(1)
LightGrid.Columns(1).LastSortState = Ascending
Cursor = Cursors.Default
LightGrid.StatusRowText = ""
LightGrid.Select()
End Using
Using (Me) on each control:
Cursor = Cursors.WaitCursor
Me.RadioButtonSortBySurname.Checked = True
Me.LightGrid.SortColumn(2)
Me.LightGrid.Columns(2).LastSortState = Ascending
Me.LightGrid.SortColumn(1)
Me.LightGrid.Columns(1).LastSortState = Ascending
Cursor = Cursors.Default
Me.LightGrid.StatusRowText = ""
Me.LightGrid.Select()
There is one case where you have to use it, to help the compiler when the variable name is ambiguous:
Sub Foo(ByVal bar As Integer)
Me.Bar = bar
End Sub
Which assigns a field in the class from an argument that has the same name. Without Me. it assigns the argument value to itself, which compiles but is never what is intended. Not so uncommon in vb.net since it is case insensitive. Otherwise recommended, it can be painful to think of an argument identifier name that is different from the field name. Some programmers (and tools) favor always giving the field name a leading underscore to avoid this problem.
But the ones you presented in your question are a matter of personal taste. There are two benefits to prefixing Me., it helps code readability since it indicates scope and narrows down where the reader has to look for the declaration. And it really helps the IntelliSense popup narrow down the list of candidates, the feature I personally care about a great deal. It is up to you.
The decision is only yours, all ways are acceptable, but... Some tools Like ReSharper recomends you to don't use the Me (VB) or this (C#) keyword to make your code more legible and smaller.
In my case I avoid using the Me keyword, but as I said, the decision is only yours.
The ME is implied if you do not specifically use it. As Hans mentioned, sometimes you HAVE to use it because the scope of ME will be overridden by closer scoped names.
Like the others I only use it infrequently, usually when I cant remember what I called some control I just added two minutes ago... then I take it out again just because I don't care for the grammar LOL. I would have preferred "THIS" rather than ME.
Related
as far as I know, I have to rename variables used in my VBA code "manually" using the search/replace function in the VBA editor (at least if I don't use an add-on like V-Tools, Speed Ferret, Rubberduck, etc.). "Replace all", which would be quick, might give you unwanted results in some cases. So you have to go through each instance manually always reorienting yourself where the search function jumped to etc.
So my question is: is there another, less time consuming, way? Maybe without the search&replace? Or maybe there an easy to remember pattern how to name a variable (object, function, procedure, etc.) so you are sure that the "replace all" option won't give you any unwanted results?
Thanks and Cheers!
First of all, make sure you use Option Explicit. When you do that, you can be slightly less careful while renaming - compiling your code will make sure that you didn't miss any variable names.
Second - use a good text editor to do your replace and create good regexes to identify your names. Expressions that make sure that you don't have the name as a part of another name.
Update after comment
Here's a little snippet to help you with export (and/or code analysis directly in VBE):
Sub AllCode()
Dim Component As Object
For Each Component In Application.VBE.ActiveVBProject.VBComponents
With Component.CodeModule
For i = 1 To .CountOfDeclarationLines
Debug.Print .Lines(i, 1)
Next i
For i = .CountOfDeclarationLines + 1 To .CountOfLines
Debug.Print .Lines(i, 1)
Next i
End With
Next
End Sub
After converting code from VB6 to VB.NET I got the following resultant code:
Designer Form Code:
Public WithEvents Timer1 As Microsoft.VisualBasic.Compatibility.VB6.TimerArray
Me.Timer1 = New Microsoft.VisualBasic.Compatibility.VB6.TimerArray(components)
Code Implementation:
Private Function GetBaseControl(ByRef a_type As String) As System.Windows.Forms.Control Implements GetBaseControl
Select Case a_type
Case "Web"
GetBaseControl = ctBrowser1(0)
Case "Timer"
GetBaseControl = Timer1(0)
End Select
End Function
Here the Error I've received:
Value of type 'Boolean' cannot be converted to 'System.Windows.Forms.Control' at Line GetBaseControl = Timer1(0).
That works fine in VB6 Though !!
If this ever worked in VB6, the code was following some very poor practices to return the Boolean Enabled instead of the actual Timer component. It implies, at minimum, that Option Strict was off, and that's really bad.
In this case, Timers in .Net are no longer considered Controls at all. Instead, they are Components. You'll want to re-think how this code functions. An example of how the code is used might let us recommend a different (better) approach to the problem.
In this case, I suspect re-thinking this to use overloaded methods (which was not idiomatic for vb6) will produce better results, especially with regards to preserving type safety rather than passing strings around.
Note: this answer made more sense before the question was edited the next day
I have simple loop:
For Each Pla As Player In Game.Players
Dim JustForTest As String
JustForTest = If(Pla.Name, Continue For)
Console.WriteLine(JustForTest)
Next
If the player's name is nothing, it should skip to the next item(or player), but I got this error at "Continue For":
BC30201 Expression expected.
Of course I can use like this:
For Each Pla As Player In Game.Players
If Pla.Name = nothing then
Continue For
end if
Console.WriteLine(Pla.Name)
Next
But I'm just curious what I was doing wrong, or is it a bug in VB?
The If Operator expects an Object to be passed into it as arguments, not a control statement. It is meant to be an equivalent to the ternary operator you'll find in other programming languages. You are trying to assign the value Continue For to your JustForTest variable -- and that just doesn't make sense.
It's not a bug in VB, just you trying to use the operator for something it's not designed to do.
The best way to compare to the Nothing (null in C#) is to use the Is or IsNot comparers, like: If obj Is Nothing Then. If your Name property is supposed to be a string then it is better if you use a String function like String.IsNullOrEmpty().
Your continue For looks correct according to the documentation.
https://msdn.microsoft.com/en-us/library/5z06z1kb.aspx#Anchor_4
I'm not an IT professional so apologies if I've missed something obvious.
When writing a program I add a class SettingsIni that reads a text file of keys and values. I find this method really flexible as settings can be added or changed without altering any code, regardless of what application I have attached it to.
Here's the main code.
Public Shared Sub Load()
Using settingsReader As StreamReader = New StreamReader(System.AppDomain.CurrentDomain.BaseDirectory & "settings.ini")
Do While settingsReader.Peek > -1
Dim line As String = settingsReader.ReadLine
Dim keysAndValues() As String = line.Split("="c)
settingsTable.Add(keysAndValues(0).Trim, keysAndValues(1).Trim)
Loop
End Using
End Sub
Public Shared Function GetValue(ByVal key As String)
Dim value As String = settingsTable(key)
Return value
End Function
This allows you to use a setting within your code by calling the SettingsIni.GetValue method.
For example:
watcher = New FileSystemWatcher(SettingsIni.GetValue("inputDir"), "*" & SettingsIni.GetValue("extn")).
I find this makes my code esay to read.
My problem is the values in this case, inputDir and extn, are typed freehand and not checked by intellisense. I'm always worried that I may make a typo in an infrequently used branch of an application and miss it during testing.
Is there a best practice method for retrieving settings? or a way around these unchecked freehand typed values?
A best practice for your code example would be to use Constants for the possible settings.
Class Settings
Const inputDir as String = "inputDir"
Const extn as String = "extn"
End Class
watcher = New FileSystemWatcher(SettingsIni.GetValue(Settings.inputDir), "*" & SettingsIni.GetValue(Settings.extn))
I assume you are using VB.NET?
If so, there is the handy "Settings"-menu under "my project". It offers a way to store the settings for your program and retrieve them via "my.settings.YOURKEY". The advantage is, that type securtiy is enforced on this level.
Additionally, you can also store "resources" almost the same way - but resources are better suited for strings / pictures etc. But they are expecially good if you want to translate your program.
As for your current problem:
Store the path in the settings, this way you do not need to change alll your code immidiately but you can use your system and never misspell anything.
If it's a number you could do these 3 things:
Check if is numeric - using IsNumeric function
Check if it is whole number - using Int function, like: if Int(number)=number
Check for the valid range, like: if number>=lowerbound and number<=upperbound
It totally depends on you. You are the one to check almost all the things inside quotes, not the intellisense.
But you still use Try-Catch block:
Try
Dim value As String = settingsTable(key)
Return value
Catch ex As Exception
MsgBox(ex.ToString)
Return ""
End Try
So you will get an message box if you are trying to access a non-existing setting that you may have mistyped.
As my first language and as completely taught from other's example I never questioned the standard practice in VBA of grouping all variable declarations at the start of the module, routine or function they are scoped to as in this example.
Sub Traditional()
Dim bVariable as Boolean
Dim OtherVariable
' Some code using OtherVariable goes here
'
' Now we use bVariable
bVariable = True
Do While bVariable
bVariable = SomeFunction()
Loop
End Sub
Now I'm learning that standard practice in other languages is to declare variables as close to where they are used as possible, like this:
Sub Defensive()
Dim OtherVariable as String
' Some code using OtherVariable goes here
'
' Now we use bVariable
Dim bVariable as Boolean
bVariable = True
Do While bVariable
bVariable = SomeFunction()
Loop
End Sub
This seems completely sensible to me as a defensive programming practice - in that it limits both span and live time (as explained in Code Complete), so I'm wondering if there is any reason for not doing the same in VBA? Possible reasons I can think of are memory, running time (e.g. repeatedly declaring inside a loop), tradition - arguably a good reason as there must be hundreds of thousands of VBA programmers who expect to see all used variables at the start of the routine. Are there any I've missed that might explain the benefit of this practice or at least where it came from?
I declare all my variables at the top. I think declaring them closer to first use masks (at least) two other problems that should be fixed first.
Procedures too long: If you're procedure is more than fits on a screen, perhaps it's doing too much and should be broken into smaller chunks. You'll also find that unit tests are way easier to write when your procedures are small and only do one thing.
Too many variables: If you have a bunch of related variables, consider using a custom class module or user-defined type. It will make the code more readable and easier to maintain.
If your procedures are short and you're using classes and UDTs, the benefits of declaring the variables at the point of use are lessened or eliminated.
I think both way are just different coding style in VBA
In old C Standard, all Declaration must be on the top, I think many people just adopt this habit and bring it into other PL such as VBA.
Declaring variable on the top is clear for short list of variable names. It will be unreadable for a long list of variable name
Declaring variable close to where it's being used is introduced later. I think this practice has a clear advantage over "declare on the top" for PLs that has optimizer or more scope than VBA. (Like you can declare variables where the scope is visible in a FOR loop only) Then the optimizer will change the scope for you. (In VBA words, it may change a GLOBAL variable to a PROCEDURE variable)
For VBA, no perference