For ple, in the following code, that fact that the variable on the left is a form frm and the value on the right exam-is an integer int should raise a warning flag for you: mfrmPlaces =
Trang 1Coding Standards
Coding standards are rules that developers follow to make their code more consistent Consistentcode is easier to read, so developers can understand and modify it more quickly with less chance
of introducing new errors
For example, suppose I build an application that uses a First Name text box My particular set ofstandards says the text box should be named txtFirstName, the associated label should benamed lblFirstName, and, if I need to copy the text entered in the text box into a variable,the variable should be named first_name If I see any of those items (txtFirstName,lblFirstName, or first_name) in the code, I know exactly what they are Similarly, if I see itemssuch as txtStreet, lblBillingCity, or cboState, I immediately know what the values are for,even without studying the code in detail That makes my understanding of the code faster andmore accurate
The object names in the previous paragraph use standard prefixes to indicate the types of objects that they represent These are txtfor TextBox, lblfor Label, and cbofor ComboBox The section “Component Names” later in this chapter lists other object prefixes.
It is important that all of the programmers on your project follow the same coding standard so thatthey can more easily read and understand each other’s code It is less important, however, whatstandard you adopt Consistency is the important thing, not whether you name variables using
“Pascal case” (FirstName), “camel case” (firstName), or lowercase with underscores(first_name) The important thing is that all of the developers follow the same rules
Standards are also useful for preventing arguments As strange as it seems, some developers canbecome quite heated when discussing the merits of Hungarian notation, camel casing, and theother niceties of coding conventions Having a well-defined standard can defuse some of thesearguments before they start
I’ve never worked on a project where these sorts of arguments were much of an issue If someone found a situation that wasn’t covered by the standard, we took a quick poll to see what the devel- opers preferred and added it to practice.
Trang 2In fact, that’s the approach I suggest you take for dealing with unexpected items If you don’t have a
rule to cover the situation, create one It doesn’t matter much what decision you make, as long as you make one.
This chapter describes my particular set of coding standards It also describes some standards mended by Microsoft developers and others After you study the different standards, you can use theirideas to write your own standard that best suits your needs
recom-Names
Most Visual Basic statements include the names of subroutines, functions, variables, modules, ated types, and other program items defined by the user Because programmers spend so much timereading these items, their names must be as easy to understand as possible If the reader must spendeven a tiny amount of extra time remembering what a name means, it can take a lot longer to under-stand the code
enumer-Picking good names can have a large impact on how easy it is to understand and maintain code, sodevelopers have spent a lot of time and effort on naming conventions The following sections describesome of the rules I use when naming variables
Hungarian Notation
Hungarian notation is a system where you add characters to the beginning of a variable’s name to give
extra information about its data type and scope For example, the variable mblnReadywould be a module-scope (m) Boolean (bln) variable, and gaintCustomerIdswould be a global (g) array (a) ofintegers (int)
The idea behind Hungarian notation was to make up for lenient compilers A loosely typed languagesuch as Visual Basic 6 will let you assign an integer variable to a string value, or vice versa For that mat-ter, it will let you put an integer or string value in a form variable, and it won’t tell you there is a poten-tial problem until the code actually tries to make the assignment at run-time
If you use proper Hungarian notation, you should notice the problem as you write the code For ple, in the following code, that fact that the variable on the left is a form (frm) and the value on the right
exam-is an integer (int) should raise a warning flag for you:
mfrmPlaces = intOrderCenters
If you take Hungarian notation to the extreme, you should never have variables in the same assignmentstatement that have different data types You should not even assign an integer value to a long integervariable without explicitly using a conversion operator such as CLngor CType
Although the motivation behind Hungarian notation is reasonable, I have rarely seen type and scopemismatches cause problems However, I have often seen developers greatly confused by badly namedvariables If you give variables good enough names, it is easier for the reader to remember what theyrepresent In many cases, the name can help the reader remember the data type as well
Trang 3For example, if the integer variable in the previous example were named num_order_centers, it would
be fairly obvious that it was a number and should not be assigned to a form variable
The Visual Basic NET environment has also become much better at warning you when you try to makesuspicious assignments For example, it will raise an error if you try to assign an integer to a form vari-able This makes Hungarian notation less important than it was in the past and, in fact, the Visual Basicdocumentation explicitly recommends that you not use it
In fact, I wish Visual Basic were even stricter than it is For example, it won’t let you implicitly assign a long integer value to an integer variable because the long value might be too big to fit in an integer (this
is called a “narrowing conversion” because the long is bigger or wider than the integer) However, it will let you assign an integer value to a long variable (a “widening conversion”) I would rather at least see an error message so that I have to think about the assignment and explicitly use CLngto make the conversion safely.
Some developers would flag these issues as warnings instead of as errors But if you ignore a bunch of warnings, it’s difficult to sift out the ones that are important from those that aren’t I would rather fix every such instance with CLng, CType, DirectCast, or other conversion statements and not see a warning or error again My goal is always to have no warnings or errors ever.
For all of these reasons, I recommend that you don’t use Hungarian notation It adds clutter to variablenames and doesn’t really help all that much Instead, focus on making the rest of the name as descriptive
as possible so that the reader can remember what the variable means The following sections give sometips on making variable names easy to remember
Component Names
Components are different from other variables used in the code because you do not declare them yourself
in your code Instead, they are created on a form and the code can then refer to them The fact that theyare declared in this special manner gives them a slightly different status than variables declared withinthe code
Components are also very important to Visual Basic programs, and code often sets a variable’s valueequal to some property of a component To make the link between a component and its correspondingvariable obvious, you should give them names that are similar For example, you might store the textvalue taken from the txtFirstName TextBoxin the variable first_name
Visual Basic developers often use three-letter prefixes to indicate a component’s type For example, dard abbreviations include txtfor TextBox, lblfor Label, btnfor Button, and so forth
stan-The more recent versions of Visual Basic have added new controls that don’t have intuitive three-letterabbreviations For example, in Visual Basic 6, the Common Dialog Control’s methods allowed the user toselect a color, font, file for saving, or file for loading It also provided methods for displaying help or aprint dialog The prefix for this control in Visual Basic 6 was dlg
Visual Basic 2005 uses separate components to handle these tasks: ColorDialog, FontDialog,OpenFileDialog, SaveFileDialog, HelpProvider, and PrintPreviewDialog You could give themobscure prefixes such as cd, fd, ofd, sfd, hp, and ppd, but it would probably take awhile to grow accus-tomed to them
Trang 4Instead, I prefer to use slightly longer abbreviations that are easier to read For these controls, I preferthese prefixes: dlgcolor, dlgfont, dlgopen, dlgsave, hlp, and dlgppv The leading “dlg” on all ofthem (except the HelpProvider) makes it obvious that the component is a dialog The rest of the prefixhelps you remember which kind of dialog.
If you really want to save a few keystrokes, you can abbreviate the abbreviations to dlgclr, dlgfnt,
dlgopn, dlgsav, hlp, and dlgppv I prefer to keep the names a little easier to read and let
IntelliSense do the typing for me.
The following table lists some suggested prefixes for the most common Windows forms components
Component Abbreviation Component Abbreviation
Trang 5For constants, I use uppercase words separated by underscores, as in the following example:
Const MAX_USERS As Integer = 10This makes it obvious that a value is a constant Unfortunately it doesn’t indicate the constant’s scope
A constant looks the same whether it is declared within a subroutine, at the module level, or globally Ihave rarely found this to be a problem, however, at least partly because constants make up such a smallfraction of the symbols in a typical application It’s just not that hard to track down a constant on thoserare occasions when you need to know where it was declared
Routine Variable Names
I declare variables within a subroutine using lowercase with underscores separating words, as shown inthe following example:
Dim num_items As IntegerDim total_cost As DecimalDim sales_tax As DecimalParameters to a routine are declared within the context of the routine, so I treat them as routine-levelvariables and also declare them using lowercase with underscores separating words For example, inthe following code, the file_pathand file_titleparameters follow this naming convention:
Public Sub LoadData(ByVal file_path As String, ByVal file_title As String)
End Sub
Component Abbreviation Component Abbreviation
Trang 6Other Names
For names that are not constants and that are not declared within routines, I use Pascal case (with thefirst letter in each word capitalized) For example, a method that generates a new invoice might be calledGenerateNewInvoice
Items whose names appear in Pascal case include namespaces, modules, classes, properties, methods,events, Enums, Enum values, module-level variables, global variables, events, and interfaces
I prefix module-level variables with “m_” and global variables with “g_” to indicate their scope Forexample, the following code declares a variable for use within a class:
Private m_DataIsDirty As Boolean
Public variables declared with a class have normal Pascal case names with no leading scope indicator
Using scope indicators is a common technique used by many Visual Basic developers, but I’ve seen
some strange uses On one large project that had been running for a very long time, some of the opers clearly didn’t understand what the m_meant, and you could find variables declared inside sub-
devel-routines that began with m_ Because the rule wasn’t applied consistently, it was almost useless.
Like most developers, I add the letter “I” before an interface name For example, an interface for able objects might be called IDrawable
draw-I do not add a “C” before class names as in CEmployeeor CCustomer, although many developers do this Microsoft recommends that you do not.
When I define an enumerated type, I add “Types” to the end of the name That lets me use the samename (minus the “s” in “Types”) as the name of a property having that type For example, the followingcode uses the ShapeTypesenumeration that defines some shape types The ShapeTypeproperty hastype ShapeTypes
Public Enum ShapeTypes
LineEllipseRectanglePolygonEnd Enum
Private m_ShapeType As ShapeTypes
Public Property ShapeType() As ShapeTypes
GetReturn m_ShapeTypeEnd Get
Set(ByVal value As ShapeTypes)m_ShapeType = valueEnd Set
End Property
Trang 7The code implements this property by using a private variable named m_ShapeType This variable hasthe same name as the property with the m_ scopeindicator to show that it is private to this class.
Boolean Names
When you declare something that has a Boolean data type, give it a name that includes a form of theverb “to be.” Use normal capitalization rules to indicate the item’s type and scope as usual (for example,is_running, is_dirty, WasHandled, or m_WillBePrinted)
The name should sound like a statement of truth and not a question If the value does not refer to the
“current” object, you may need to put the form of “to be” inside the name, rather than at the beginning ifyou want it to sound like a statement
For example, in the Orderclass the IsDirtyproperty indicates that the Order’s data has changed Theproperty applies to the current Orderobject, so the statement IsDirtymakes sense for that object
If an Orderobject’s code refers to several printers, it might use the variables printer1_is_ready,printer2_is_ready, and so forth, to refer to their readiness The names is_printer1_ready,is_printer2_ready, and so on, sound more like questions than statements
The final test is to try the name out in a Boolean expression The following statement is fairly easy toread:
If printer1_is_ready Or printer2_is_ready Then
The following statement is more awkward:
If is_printer1_ready Or is_printer2_ready Then
This version is harder to read, so it will take longer to read and is more likely to lead to misunderstanding
num_employees, num_emps, or no_emps
In practice, however, some abbreviations are extremely common The NET Framework uses minandmaxto mean “minimum” and “maximum” in several places, so those seem like safe abbreviations Manydevelopers also use numfor “number” so that also seems reasonably safe
In some applications, it may also make sense to use industry-specific abbreviations When I was ing at a GTE Laboratories, abbreviations such as pots (Plain Old Telephone Service) and mark (referring
work-to another application, Mechanized Assignment and Record Keeping) were common
Trang 8To keep things consistent, make a list of allowed abbreviations and add to it when necessary Try to spellwords out and use IntelliSense to make typing them easier However, if everyone in the office alreadyuses certain abbreviations, it sometimes makes the code more consistent and easier to read to use them
in the program as well
Escaped Names
Visual Basic allows you to use keywords in names by surrounding the name in square brackets The lowing code shows a function named Subthat takes a parameter named New The code uses brackets todifferentiate these names from the Visual Basic keywords Suband New
fol-Private Function [Sub](ByVal [New] As Integer) As Integer
If [New] < 10 Then [New] = 10
If [New] > 100 Then [New] = 100Return [New]
This code is confusing and difficult to read Don’t use escaped names unless absolutely necessary
The only situation I know of when you really need to use escaped names is when you are using a library
or other tool that uses Visual Basic keywords for names For example, C# does not have the ReDimword, so it is possible that someone writing a library in C# might create a class named ReDim To usethat class in Visual Basic, you must surround the name with brackets, as in the following statement:
key-Dim redimmer As New [Rekey-Dim]
Even then you could use the library’s fully qualified name, as in this version:
Dim redimmer As New ReDimLib.ReDim
The ReDimLibexample solution available for download at www.vb-helper.com/one_on_one.htmincludes a C# library that defines a simple ReDimclass and a Visual Basic program that uses it
I’ve never heard a plausible reason why you would need to use keywords for names in code that youwrite
Trang 9Property Names
Make the names of properties nouns or noun phrases such as TextColor, LineWidth, orStraightness A property is a characteristic of an object, and these names sound like characteristics.Microsoft recommends that you consider naming properties after their data types, if that makes sense.For example, if a class needs a font property, you could name it Font The following code shows how aclass might declare a Fontproperty of type Font:
Private m_Font as FontProperty Font() As FontGet
Return m_FontEnd Get
Set(ByVal value As Font)m_Font = valueEnd Set
End PropertyThis can sometimes lead to confusion (particularly because it’s not as easy to make a property namedafter an enumerated type that you create within the class), so I usually prefer to change the nameslightly For example, you could change this property’s name to TextFont
Method Names
A subroutine makes an object do something, so its name should reflect that by indicating an action Givesubroutines names that are verbs or verb phrases For example, some good subroutine names includePrintInvoices, DeleteItem, and Execute
Avoid names that could be interpreted as either nouns or verbs For example, don’t use the name Colorfor a subroutine that colors a shape, because someone reading the code might read Coloras a noun andassume it is a property rather than a subroutine
Usually, you can avoid this issue by adding an extra word In this case, you could change the tine’s name to ColorShape
subrou-A function is similar to a subroutine except that it returns a value Because a function returns a value, it
is usually more natural to treat the function as a noun instead of a verb For example, the following codecalls the driving_mapobject’s BestForeColorfunction and saves the result in a form’s ForeColorproperty:
Me.ForeColor = driving_map.BestForeColor()
In cases such as this one, there is practically no difference between a function and a read-only property.Both make the most sense with names that are noun phrases, both return a value, and you cannot assign
a value to either
Trang 10Sometimes it’s difficult to decide whether to implement a feature as a function or a property The ing list gives some reasons why you might want to choose one or the other:
follow-❑ If the action is a conversion function such as ToString, Microsoft recommends that you use afunction
❑ If the action takes a long time, use a function Properties are expected to be fast
❑ If the action has side effects, use a function Properties should not have side effects
❑ If the action returns an array, use a function Properties that return arrays can be confusing
❑ If you want to serialize the value, use a property
❑ If you want to display values in a PropertyGridor other property editor, use a property This
is most useful if the developer must set the value at design time, or if the user must set it at run-time
❑ If you want to notify the program when the value changes, use a property and an associatedproperty changed event For example, if the program might need to know when theMinimalPathLengthvalue changes, make it a read-only property and raise theMinimalPathLengthChangedevent when it changes It is more natural and traditional to asso-ciate an event with a property than with a function
Event Names
For events that occur before the code takes some action, end the event’s name with the “ing” form of averb, as in Clicking, Changing, Moving, or Canceling For events that occur after the code takes someaction, end the event’s name with a verb in the past tense, as in Clicked, Changed, Moved, or Canceled
Make the rest of the name explain the thing to which the verb applies — for example, SeatClicked,CustomerChanged, DrawingObjectMoved, or JobSchedulingCanceled
Microsoft recommends that you add EventHandlerto the end of event handler names, as in the ing code:
follow-Public Delegate Sub SeatClickedEventHandler(ByVal seat_clicked As Seat)
This makes sense when you are declaring a delegate Later, when you declare a variable with the gate’s type, the name makes it easier to understand that this is an event handler
dele-Dim clicked_event_handler As SeatClickedEventHandler
In Visual Basic, it is traditional to name an event handler by using the name of the object raising theevent, followed by an underscore and then the name of the event The Visual Basic code editor namesevents this way if you use the drop-downs to build an event handler The event handler name is thesame as the name in the Handlesclause, except the dot is replaced with an underscore
The following code shows how the code editor would name the SeatClickedevent raised by an objectnamed m_SeatingChart:
Trang 11Public Sub m_SeatingChart_SeatClicked(ByVal seat_clicked As Seat) _Handles m_SeatingChart.SeatClicked
End SubSometimes you might want to create an event handler yourself without using the code editor’s drop-downs For example, suppose you create several Drawableobjects at run-time, and you want to useAddHandlerto associate them all with an ObjectMovedevent handler To make the event handler’sname consistent with the code editor’s naming style, end the name with an underscore and the eventname
Start the name with a phrase that describes the objects that raised the event For example, if the programkeeps the objects in a collection or array, you could use the collection or array’s name The followingshows an example:
Public NetworkObjects As List(Of Drawable)Private Sub NetworkObjects_DrawableMoved(ByVal sender As Drawable)MessageBox.Show(sender.Name)
End SubPrivate Sub Form1_Load(ByVal sender As System.Object, _ByVal e As System.EventArgs) Handles MyBase.LoadDim new_drawable As Drawable
For i As Integer = 1 To 10new_drawable = New DrawableAddHandler new_drawable.DrawableMoved, _AddressOf NetworkObjects_DrawableMovedNext i
End SubThe code starts by declaring a list of Drawableobjects The event handler that catches the objects’DrawableMovedevents is named NetworkObjects_DrawableMoved The name consists of the name ofthe list NetworkObjectsfollowed by an underscore and the name of the event: DrawableMoved
The form’s Loadevent handler adds some Drawableobjects to the list and uses AddHandlerto ate the NetworkObjects_DrawableMovedevent handler with the objects’ DrawableMovedevents
associ-Declaring Variables
In Visual Basic 6 and earlier versions, it was common practice to declare all variables at the beginning of
a routine If you were reading code and needed to remember how a variable was declared, you couldeasily find it at the beginning of the routine
In Visual Basic NET, the custom has shifted to declaring variables as close as possible to the place wherethey are used Often, that means you can see the variable’s declaration whenever you are reading thecode that uses it There are still plenty of times where a long piece of code uses variables that weredeclared much earlier, but at least some of the time you can keep the declaration in view while the vari-able is used
Trang 12Placing variables close to where they are used fits well with newer statements that allow you to declarevariables inside a more limited scope For example, the Forstatement can declare its looping variable sothat the variable only exists within the loop Similarly For Each, Using, Catch, and other statements letyou define variables that only exist within their blocks.
Declarations in Visual Basic NET also allow you to initialize variables when they are declared This is agood practice because it ensures that the variable is initialized before it is used (and it avoids VisualBasic warning you about a possibly uninitialized variable) Initializing all variables at the beginning of aroutine often seems strange because the value you use for the initialization doesn’t make much sense(and, in fact, may not exist) until later when the variable is used
Many developers still prefer the older system of declaring variables at the beginning of the routine, and Ican’t say with certainty that they’re wrong I’ve used both methods for a long time, and I prefer thenewer “declare when needed” style, but both systems can work You should try them both and decidewhat works best for you and your development team
If you can’t see a variable’s declaration, you can right-click it and select Go To Definition to jump to the variable’s declaration.
As an added tip, insert an @ character in the code before you jump to the declaration Then, if the ration is in the same file, you can press Ctrl+Z to undo the insertion of the @ and get back where you
decla-started If moving to the declaration made you switch modules, Ctrl+Z won’t undo changes in the ule where you started, but you can find the @ character in Visual Studio’s Error List.
mod-Declaring variables close to the code that uses them helps restrict their scope so that you don’t need toworry about what the variable is for in other code An even better way to restrict scope is to declare vari-ables within a block of code For example, a variable declared inside a Forloop, Doloop, If Thenblock,Caseblock, Try Catchblock, or other block of code is visible only within that code That means youdon’t need to think about the variable outside of the block, you don’t need to worry about code outside
of the block modifying the variable, and you can even reuse the variable name in other blocks of code
The following code declares the variables test_seatand seat_statuswithin the Forloop so thatthey are only visible within the loop You don’t need to worry about what those variables do and whatvalues they contain while you are looking at the code outside of the loop
‘ Examine the seats
For seat_num As Integer = 0 To num_seats – 1
Dim test_seat As Seat = AllSeats(seat_num)Dim seat_status As SeatStatus = test_seat.Status
Next seat_num ‘ End examining the seats
When you write a Forloop, the looping variable is often an index and has little real purpose other thancontrolling the loop The variable doesn’t mean anything by itself, so it usually has a non-descriptivename such as i, j, or x Whenever possible, declare these variables in the Forstatement That restrictsthe variable’s scope to the loop, while still allowing you to reuse the variable in other loops
The following code declares the variable iin the Forstatement:
Trang 13‘ Print the employees’ work assignments.
For i As Integer = 0 To num_employees – 1
‘ Print this employee’s work assignment
Next iThe Usingstatement introduced in Visual Basic 2005 takes this idea a step further Visual Basic not onlymakes variables declared in a Usingstatement local to the block, but it also automatically calls the vari-ables’ Disposemethod when the block ends Of course, that means the variables must represent objectsthat have a Disposemethod such as a Pen, Brush, Control, or Formobject
When the code is done with an object, calling Disposemakes it free resources that it is using, and makes garbage collection more efficient It is not strictly necessary, but improves performance and limits the variable’s scope, so it’s worthwhile.
The following code draws a thick ellipse on a form The Usingstatement creates a Penobject that is blueand 15 pixels thick Inside the Usingblock, the code draws an ellipse within the form’s client rectangle
Private Sub Form1_Paint(ByVal sender As Object, _ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.PaintUsing thick_pen As New Pen(Color.Blue, 15)
e.Graphics.DrawEllipse(thick_pen, Me.ClientRectangle)End Using
End SubWhen the Usingblock ends, the Penis Disposedand the variable is destroyed
If the Usingblock is long, add a comment at the end reminding the user of the variables created by theUsingstatement and of the block’s purpose
Another feature introduced in Visual Basic NET is the ability to initialize variables in their declarations.The following code fragment declares two Customerobject variables It sets the first one to a newCustomerobject and explicitly sets the second to Nothing The code then declares an Integerthat itsets to 10and a Stringthat it sets to an empty string
Dim test_customer As New Customer(“Carson”, “Repins”)Dim new_customer As Customer = Nothing
Dim max_allowed_items As Integer = 10Dim order_summary As String = “”
Experienced developers know what values Visual Basic uses to initialize variables by default and times take advantage of this fact For example, they know that object variables, such as the two
some-Customervariables in the previous code, are initialized to Nothing They also know that Integerables are initialized to 0 It’s less obvious that string variables are initialized to Nothingrather than anempty string
vari-Though you may know the values that Visual Basic uses to initialize variables, it’s much less obvious tosomeone reading the code later, whether you knew those values and were relying on them, or whetheryou just missed something To avoid possible confusion, always initialize variables explicitly and do so
in their declarations, if possible That way, a variable’s value is explicitly set in the code as soon as thevariable is declared, so there can be no surprises